FALLOCATE(2)

ИМЯ
fallocate - управление пространством файла

ОБЗОР
#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 больше чем размер файла. Это полезно для предварительного выделения блоков с нулями за концом файла для оптимизации загруженности при добавлении.

Если в modeуказан флаг FALLOC_FL_UNSHARE, то общие файловые extent-данные будут сделаны частными для файла, чтобы гарантировать, что последующая запись не завершится ошибкой из-за нехватки места. Обычно, это выполняется с помощью операции копирования при записи для всех общих данных файла. Данный флаг может поддерживаться не во всех файловых системах.

Так как выделение выполняется кусками размером с блок, 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(5) (начиная с 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)

*   Btrfs (начиная с Linux 4.16)

  Увеличение файлового пространства
Задание флага 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.

СМОТРИТЕ ТАКЖЕ
fallocate(1), ftruncate(2), posix_fadvise(3), posix_fallocate(3)