fallocate(2) управление пространством файла

ОБЗОР

#define _GNU_SOURCE /* Смотрите feature_test_macros(7) */
#include <fcntl.h>
int fallocate(int fd, int mode, off_t offset, off_t len);

ОПИСАНИЕ

Это непереносимый системный вызов, существующий только в Linux. В POSIX.1 есть переносимый метод, обеспечивающий выделение пространства под файл (смотрите posix_fallocate(3)).

Вызов fallocate() позволяет вызывающему напрямую управлять выделением дискового пространства под файл, на который указывает fd, для байтового диапазона, начинающегося с offset и имеющего длину len байт.

В аргументе mode задаётся операция, выполняемая над указанным диапазоном. Детали о поддерживаемых операциях представлены в подразделах далее.

Выделение дискового пространства

По умолчанию (т. е. значение mode равно нулю) fallocate() выделяет место на диске в диапазоне, задаваемом offset и len. Размер файла (получаемый через stat(2)) будет изменён, если offset+len больше чем размер файла. Любая подобласть внутри диапазона, заданного offset и len, которая не содержала данных до вызова, будет заполнена нулями. Такое поведение по умолчанию очень напоминает поведение библиотечной функции posix_fallocate(3), и было введено для оптимальной реализации этой функции.

После успешного выполнения вызова последующие операции записи в диапазон, указанный offset и len, гарантированно не завершатся с ошибкой из-за нехватки места на диске.

Если в mode указан флаг FALLOC_FL_KEEP_SIZE, то поведение по умолчанию почти то же, но размер файла не будет изменён даже, если offset+len больше чем размер файла. Предварительно выделенные блоки с нулями за концом файла в этом случае полезны для оптимизации добавления.

Так как выделение выполняется кусками размером с блок, fallocate() может выделить больший диапазон дискового пространства, чем было указано.

Освобождение файлового пространства

Указание флага FALLOC_FL_PUNCH_HOLE (доступен, начиная с Linux 2.6.38) в mode освобождает пространство (т.е., создаёт дыру) в диапазоне начиная с offset и до len байт. Внутри заданного диапазона неполные блоки файловой системы заполняются нулями, а полные блоки файловой системы удаляются из файла. После успешного выполнения вызова, последующие операции чтения из этого диапазона вернут нули.

Флаг FALLOC_FL_PUNCH_HOLE должен быть логически добавлен к флагу FALLOC_FL_KEEP_SIZE в mode; другими словами, даже когда пробивание (punching) выходит за конец файла, размер файла (получаемый с помощью stat(2)) остаётся неизменным.

Не все файловые системы поддерживают FALLOC_FL_PUNCH_HOLE; если файловая система не поддерживает эту операцию, то возвращается ошибка. Операция поддерживается, как минимум, следующими файловыми системами:

*
XFS (начиная с Linux 2.6.38)
*
ext4 (начиная с Linux 3.0)
*
Btrfs (начиная с Linux 3.7)
*
tmpfs (начиная с Linux 3.5)

Сворачивание (Collapsing) файлового пространства

Задание флага FALLOC_FL_COLLAPSE_RANGE (доступен, начиная с Linux 3.15) в mode приводит к удалению байтового диапазона из файла без создания дыры. Сворачиваемый диапазон байт начинается с offset и длится len байт. По завершению операции, содержимое файла, начиная с offset+len, будет добавлено в расположение offset, и файл будет на len байт меньше.

У файловой системы могут быть ограничения на детализацию операции, для большей эффективности реализации. Обычно, значения offset и len должны быть кратны размеру логического блока файловой системы, различающемуся в разных файловых системах и зависящему от настроек. Если файловая система содержит такое требование и оно нарушено, то fallocate() завершится с ошибкой EINVAL.

Если область, заданная offset плюс len достигает или выходит за конец файла, то возвращается ошибка; вместо этого используйте ftruncate(2) для обрезания файла.

Вместе с FALLOC_FL_COLLAPSE_RANGE другие флаги в mode указывать нельзя.

В Linux 3.15 флаг FALLOC_FL_COLLAPSE_RANGE поддерживается в ext4 (только для файлов на основе extent) и XFS.

Зануление файлового пространства

Задание флага FALLOC_FL_ZERO_RANGE (доступен, начиная с Linux 3.15) в mode приводит к обнулению байтового диапазона, начиная с offset и размером len байт. Внутри указанного диапазона блоки выделяются заранее для областей, которые попадают в дыры в файле. После успешного выполнения вызова последующие операции чтения из этого диапазона будут возвращать нули.

Зануление, желательно, выполнять внутри файловой системы, преобразуя диапазон в незаписываемые extents. Этот подход означает, что указанный диапазон на устройстве в действительности не будет содержать нули на физическом уровне (за исключением неполных блоков в одном из концов диапазона), и ввод-вывод требуется только для обновления метаданных.

Если в mode также указан флаг FALLOC_FL_KEEP_SIZE, то поведение вызова похоже, но размер файла не будет изменён даже, если offset+len больше размера файла. Такое поведение совпадает с предварительным выделением пространства с помощью указания флага FALLOC_FL_KEEP_SIZE.

Не все файловые системы поддерживают FALLOC_FL_ZERO_RANGE; если файловая система не поддерживает эту операцию, то возвращается ошибка. Операция поддерживается, как минимум, следующими файловыми системами:

*
XFS (начиная с Linux 3.15)
*
ext4, для файлов на основе extent (начиная с Linux 3.15)
*
SMB3 (начиная с Linux 3.17)

Увеличение файлового пространства

Задание флага FALLOC_FL_INSERT_RANGE (доступен начиная с Linux 4.1) в mode увеличивает файловое пространство посредством вставки дыры (hole) в размер файла без перезаписывания существующих данных. Дыра начинается с offset и продолжается len байт. При вставки дыры внутрь файла содержимое файла, начинающееся с offset, будет сдвинуто вперёд (т. е., станет доступно по большему смещению в файле) на len байт. Вставка дыры внутрь файла увеличивает размер файла на len байт.

Данный режим имеет те же ограничения что и FALLOC_FL_COLLAPSE_RANGE, независимо от детализации операции. Если требования детализации не удовлетворяются, то fallocate() завершится с ошибкой EINVAL. Если offset больше или равно концу файла, то возвращается ошибка. Для таких операций (т. е., вставка дыры в конец файла) нужно использовать ftruncate(2).

Вместе с FALLOC_FL_INSERT_RANGE другие флаги в mode указывать нельзя.

Для работы FALLOC_FL_INSERT_RANGE требуется поддержка в файловой системе; сейчас это XFS (начиная с Linux 4.1) и ext4 (начиная с Linux 4.2).

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

При успешном выполнении fallocate() возвращается 0; при ошибке возвращается -1, а в errno содержится код ошибки.

ОШИБКИ

EBADF
Значение fd не является допустимым файловым дескриптором или он не открыт на запись.
EFBIG
Сумма offset+len превышает максимальный размер файла.
EFBIG
В mode указан FALLOC_FL_INSERT_RANGE, и текущий размер файла+len превышает максимальный файловый размер.
EINTR
При выполнении поступил сигнал; смотрите signal(7).
EINVAL
Значение offset меньше 0, или len меньше или равно 0.
EINVAL
Значение mode равно FALLOC_FL_COLLAPSE_RANGE, но диапазон, указанный в offset плюс len, достиг или перешагнул за конец файла.
EINVAL
Значение mode равно FALLOC_FL_INSERT_RANGE, но диапазон, указанный в offset, достиг или перешагнул за конец файла.
EINVAL
Значение mode равно FALLOC_FL_COLLAPSE_RANGE или FALLOC_FL_INSERT_RANGE, но значение offset или len не кратно размеру блока файловой системы.
EINVAL
Значение mode содержит FALLOC_FL_COLLAPSE_RANGE или FALLOC_FL_INSERT_RANGE, а также другие флаги; но с FALLOC_FL_COLLAPSE_RANGE или FALLOC_FL_INSERT_RANGE другие флаги указывать нельзя.
EINVAL
Значение mode равно FALLOC_FL_COLLAPSE_RANGE, FALLOC_FL_ZERO_RANGE или FALLOC_FL_INSERT_RANGE, но файл, на который указывает fd, не является обычным файлом.
EIO
При чтении или записи в файловую систему произошла ошибка ввода-вывода.
ENODEV
Значение fd не указывает на обычный файл или каталог (если fd — канал или FIFO, то возникнет другая ошибка).
ENOSPC
Недостаточно дискового пространства на устройстве, на котором расположен файл, указанный в fd.
ENOSYS
В данном ядре вызов fallocate() не реализован.
EOPNOTSUPP
Файловая система с файлом, на который указывает fd, не поддерживает данную операцию; или значение mode не поддерживается файловой системой, в которой находится файл, на который указывает fd.
EPERM
Файл, на который указывает fd, помечен как неизменяемый (immutable) (смотрите chattr(1)).
EPERM
Значение mode равно FALLOC_FL_PUNCH_HOLE, FALLOC_FL_COLLAPSE_RANGE или FALLOC_FL_INSERT_RANGE и файл, на который указывает fd, помечен как только для добавления (смотрите chattr(1)).
EPERM
Выполнение операции предотвращено опечатыванием (file seal); смотрите fcntl(2).
ESPIPE
Значение fd указывает на канал или FIFO.
ETXTBSY
Значение mode равно FALLOC_FL_COLLAPSE_RANGE или FALLOC_FL_INSERT_RANGE, но файл, на который указывает fd, в данный момент выполняется.

ВЕРСИИ

Вызов fallocate() доступен в Linux начиная с ядра 2.6.23. Поддержка в glibc добавлена в версии 2.10. Флаги FALLOC_FL_* определены в заголовочных файлах glibc только начиная с версии 2.18.

СООТВЕТСТВИЕ СТАНДАРТАМ

Вызов fallocate() есть только в Linux.