FSCTL_MOVE_FILE в Windows XP, системный том, FAT32
У меня проблема с дефрагментацией файлов на системном томе windows xp, fat32. Я не пишу дефрагментатор, но вместо этого часть решения требует, чтобы определенный набор файлов постоянно размещался на диске. Чтобы убедиться в этом, я использую FSCTL_MOVE_FILE ioctl для перемещения экстентов файлов в один экстент свободного пространства достаточного размера на томе. Процесс идет следующим образом:
1) Создайте файл:
return m_file.Create(path,
GENERIC_READ | GENERIC_WRITE,
0, NULL,
CREATE_ALWAYS,
FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH |
FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
NULL);
2) Заполнить файл нулями.
3) Убедитесь, что файл фрагментирован, если это так, приобретите растровое изображение тома с помощью FSCTL_GET_VOLUME_BITMAP, найдите свободную цепочку кластеров достаточного размера.
4) Используйте FSCTL_MOVE_FILE для дефрагментации файла в найденный экстент как таковой:
MOVE_FILE_DATA input;
input.FileHandle = fileHandle;
input.StartingVcn.QuadPart = 0;
input.StartingLcn.QuadPart = freeExtent.lcn;
input.ClusterCount = totalFileClusters;
DWORD bytesReturned = 0; // unused
::DeviceIoControl(
volumeHandle,
FSCTL_MOVE_FILE,
&input,
sizeof(input),
NULL,
0,
&bytesReturned,
NULL);
Последний вызов отлично работает в системе NTFS и на обычных томах. Несистемные тома на XP также не представляют никаких проблем. Однако на томах системы FAT32 на XP я почти всегда получаю ошибку INVALID_ARGUMENT (87). Файлы довольно большие, около 700 МБ. Объем имеет около 10 ГБ свободного места. После сбоя fsctl видно, что часть файла действительно была перемещена до возникновения ошибки. Я попробовал несколько попыток, но пока все 50 из них потерпели неудачу. Мне известно, что перемещение большого файла таким способом может завершиться сбоем из-за ранее свободного кластера, который в дальнейшем будет занят чем-то другим на томе, особенно если на нем много активности (как это обычно бывает с системными томами). Но я понятия не имею, как смягчить это, учитывая, что у меня нет ядра. Что я делаю не так и / или как я могу сделать лучше?
2 ответа
Две проблемы. Во-первых, в реальной системе вы всегда соревнуетесь с другими действиями (как предлагал предыдущий ответчик). Например, как только вы получили растровое изображение тома, оно может уже устареть из-за операций в других процессах, которые вы не видите.
Во-вторых, в FAT32 есть ограничение на то, сколько вы можете двигаться за один раз. Возможно, вам следует рассмотреть возможность перемещения файлов кусками по 256 Кб (он же размер представления отображения диспетчера кэша). Если вы столкнулись с ошибкой, такой как пробел, который раньше был свободен, у вас гораздо меньше работы, чтобы рассуждать.
Наконец, если у вас есть файл размером 700 МБ, если он существует в виде фрагментов размером 700 МБ, я сомневаюсь, что вы заметите какие-либо существенные улучшения производительности по сравнению с одним блоком размером 700 МБ.
Короткий ответ здесь - нет, вы не можете попасть туда из пользовательского режима. Вы всегда будете соревноваться с остальными процессами приложений / операционной системы, которые управляют файловой системой.
Если вы действительно хотите пойти по этому пути, вам нужно написать довольно сложный драйвер ядра (минифильтр файловой системы), чтобы помочь с синхронизацией этой операции. Это может быть сложно, особенно для перемещений на томах, где размещаются файлы подкачки / подкачки.
Удачи!