фаллокейт против posix_fallocate

Я обсуждаю, какую функцию использовать между posix_fallocate и fallocate. posix_fallocate сразу записывает файл (инициализирует символы в NULL). Однако fallocate не меняет размер файла (при использовании флага FALLOC_FL_KEEP_SIZE). Основываясь на моих экспериментах, кажется, что fallocate не записывает в файл NULL или нулевые символы.

Может кто-нибудь прокомментировать, основываясь на вашем опыте? Спасибо за ваше время.


person Bill    schedule 28.12.2012    source источник
comment
fallocate не меняет размер файла? Это для меня. В противном случае единственная разница между ними заключается в том, что fallocate будет более эффективно работать с ядрами Linux, чем posix_fallocate, хотя и не переносимым.   -  person netcoder    schedule 28.12.2012
comment
Это из документации --Предварительное выделение блоков не меняет размер файла kernel.org/doc/man-pages/online/pages/man2/fallocate.2.html   -  person Bill    schedule 28.12.2012
comment
Вы цитируете это совершенно вне контекста.   -  person netcoder    schedule 28.12.2012
comment
Я хотел сказать вот что: когда вы выделяете и проверяете размер файла, на него не влияют выделенные байты. Но если вы используете posiz_fallocate и проверяете размер файла, это влияет на размер файла. Надеюсь, это в контексте обсуждения. Я также наблюдал такое поведение в своем тестировании.   -  person Bill    schedule 28.12.2012
comment
Я знаю, что Вы имеете ввиду. Но Предварительное выделение блоков не меняет размер файла, применяется только при установленном флаге FALLOC_FL_KEEP_SIZE. Отсутствие установки флага должно дать вам тот же результат для любого из них.   -  person netcoder    schedule 28.12.2012
comment
Я обновлю вопрос.   -  person Bill    schedule 28.12.2012


Ответы (3)


Наличие файлов, которые занимают больше места для хранения, чем их отображаемая длина, не является обычным явлением, поэтому, если у вас нет веской причины для этого (например, вы хотите использовать длину файла, чтобы отслеживать, как далеко продвинулась загрузка, с целью возобновления это), лучше всего использовать поведение fallocate(2) по умолчанию. (без FALLOC_FL_KEEP_SIZE). Это та же семантика, что и у posix_fallocate(3).

На странице руководства для fallocate(2) даже говорится, что его поведение по умолчанию (без флагов) задумано как оптимальный способ реализации posix_fallocate(3), и указывает на это как на переносимый способ распределения пространства.

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

Поэтому, если вас устраивает семантика POSIX, используйте ее, потому что она более переносима. Каждая система GNU/Linux будет поддерживать posix_fallocate(3), но также и некоторые другие системы.

Однако благодаря семантике POSIX это не так просто. Если вы используете его в файловой системе, которая не поддерживает предварительное выделение, он все равно будет успешным, но сделает это, возвращаясь к фактической записи нуля в каждом блоке файла.

Программа испытаний:

#include <fcntl.h>
int main() {
    int fd = open("foo", O_RDWR|O_CREAT, 0666);
    if (fd < 0) return 1;
    return posix_fallocate(fd, 0, 400000);
}

на XFS

$ strace ~/src/c/falloc
...
open("foo", O_RDWR|O_CREAT, 0666) = 3
fallocate(3, 0, 0, 400000)              = 0
exit_group(0)                           = ?

на флешке фат32:

open("foo", O_RDWR|O_CREAT, 0666) = 3
fallocate(3, 0, 0, 400000)              = -1 EOPNOTSUPP (Operation not supported)
fstat(3, {st_mode=S_IFREG|0755, st_size=400000, ...}) = 0
fstatfs(3, {f_type="MSDOS_SUPER_MAGIC", f_bsize=65536, f_blocks=122113, f_bfree=38274, f_bavail=38274, f_files=0, f_ffree=0, f_fsid={2145, 0}, f_namelen=1530, f_frsize=65536}) = 0
pread(3, "\0", 1, 6783)                 = 1
pwrite(3, "\0", 1, 6783)                = 1
pread(3, "\0", 1, 72319)                = 1
pwrite(3, "\0", 1, 72319)               = 1
pread(3, "\0", 1, 137855)               = 1
pwrite(3, "\0", 1, 137855)              = 1
pread(3, "\0", 1, 203391)               = 1
pwrite(3, "\0", 1, 203391)              = 1
pread(3, "\0", 1, 268927)               = 1
pwrite(3, "\0", 1, 268927)              = 1
pread(3, "\0", 1, 334463)               = 1
pwrite(3, "\0", 1, 334463)              = 1
pread(3, "\0", 1, 399999)               = 1
pwrite(3, "\0", 1, 399999)              = 1
exit_group(0)                           = ?

Это позволяет избежать чтения, если файл еще не такой длинный, но запись каждого блока по-прежнему ужасна.

Если вам нужно что-то простое, я бы все равно выбрал posix_fallocate. Для него есть справочная страница FreeBSD, и он указан в POSIX, поэтому его предоставляет каждая POSIX-совместимая система. Единственным недостатком является то, что это будет ужасно с glibc в файловой системе, которая не поддерживает предварительное выделение. См., например, https://plus.google.com/+AaronSeigo/posts/FGtXM13QuhQ. Для программы, которая работает с большими файлами (например, торрентами), это может быть очень плохо.

Вы можете поблагодарить семантику POSIX за то, что она потребовала от glibc сделать это, поскольку она не определяет код ошибки для «файловая система не поддерживает предварительное выделение». http://pubs.opengroup.org/onlinepubs/009695399/functions/posix_fallocate. HTML. Это также гарантирует, что в случае успешного вызова последующие записи в выделенную область не завершатся ошибкой из-за нехватки места на диске. Таким образом, дизайн posix не обеспечивает способа обработки случая, когда вызывающая сторона заботится об эффективности/производительности/фрагментации, а не о гарантиях дискового пространства. Это вынуждает реализацию POSIX выполнять цикл чтения-записи, а не оставлять это как вариант для вызывающих программ, которым требуется гарантия дискового пространства. Спасибо POSIX...

Я не знаю, возвращаются ли не-GNU реализации posix_fallocate к чрезвычайно медленному поведению при чтении-записи, когда файловая система не поддерживает предварительное выделение. (FreeBSD, Solaris?). По-видимому, OS X (Darwin) не реализует posix_fallocate, если только он не совсем новый.

Если вы хотите поддерживать предварительное выделение на множестве платформ, но без возврата к чтению и записи, если в ОС есть способ просто попытаться выполнить предварительное выделение, вы должны использовать любой доступный метод для конкретной платформы. например проверьте https://github.com/arvidn/libtorrent/blob/master/src/file.cpp

найдите файл::set_size. Он имеет несколько блоков ifdeffed в зависимости от того, что поддерживает цель компиляции, начиная с кода Windows для загрузки библиотек DLL и других действий там, затем fcntl F_PREALLOCATE или fcntl F_ALLOCSP64, затем Linux fallocate(2), затем возвращается к использованию posix_fallocate. Кроме того, нашел этот список сообщений 2007 года для OS X Darwin: http://lists.apple.com/archives/darwin-dev/2007/Dec/msg00040.html

person Community    schedule 07.05.2014
comment
Добавлена ​​последняя версия POSIX ... или базовый файл system не поддерживает эту операцию в значении EINVAL, так что glibc и другие теперь могут реализовать posix_fallocate разумным образом. Теоретически. - person Nemo; 11.06.2015
comment
Хороший! Тем не менее, пройдет много лет, прежде чем дистрибутивы Linux с отказом от записи нулей перестанут использоваться, поэтому даже для нового программного обеспечения небезопасно предполагать хорошее поведение. Сопровождающие также могут решить, что система GNU всегда должна иметь работающую posix_fallocate, и оставить свой запасной вариант. - person Peter Cordes; 13.06.2015
comment
Полноценные дистрибутивы Linux вряд ли перейдут на возврат EINVAL для posix_fallocate, потому что glibc сохранит текущее поведение в целях совместимости на неопределенный срок. См. темы, содержащие sourceware.org/ml/libc-alpha/2015- 10/msg00138.html и sourceware.org/ml/ libc-alpha/2015-05/msg00062.html для получения подробной информации. - person Anon; 03.07.2017
comment
NFS4.2 поддерживает fallocate? Прикольно, я не понял. Однако чтение из дыры или незаписанного экстента по-прежнему отправляет нули по сети. :( - person Peter Cordes; 03.07.2017

Я так понимаю, вы не смотрели документацию, в которой говорится

   The mode argument determines the operation to be performed on the given range.
   Currently only one flag is supported for mode:

   FALLOC_FL_KEEP_SIZE
          This flag allocates and initializes to zero the disk space within the
          range specified by offset and len.  After a successful call, subsequent
          writes into this range are guaranteed not to fail because of lack of
          disk space.  Preallocating zeroed blocks beyond the end of the file is
          useful for optimizing append workloads.  Preallocating blocks does not
          change the file size (as reported by stat(2)) even if it is less than
          offset+len.

   If FALLOC_FL_KEEP_SIZE flag is not specified in mode, the default behavior is
   almost same as when this flag is specified.  The only difference is that on
   success, the file size will be changed if offset + len is greater than the
   file size.  This default behavior closely resembles the behavior of the
   posix_fallocate(3) library function, and is intended as a method of optimally
   implementing that function.

На странице руководства для posix_fallocate(), похоже, не упоминается то же самое, но вместо этого просмотр исходного кода здесь (строка 8), кажется, пишет каждый блок файла.

указать местонахождение человек posix_fallocate

person Mats Petersson    schedule 28.12.2012
comment
В настоящее время для режима поддерживается только один флаг — это может быть технически некорректно. Есть еще несколько поддерживаемых флагов -- man7.org/linux/ man-страницы/man2/fallocate.2.html - person Bill; 28.12.2012
comment
Хм, так что я думаю, что одна из проблем с миллионами копий справочных страниц по всему Интернету заключается в том, что вы никогда не знаете, когда нашли правильную... Однако на моей справочной странице Fedora Core 16 указан тот же флаг, что и цитируемый текст, поэтому я не уверен, что является более точным. Похоже, что здесь доступны два: lxr.linux.no/linux+*/fs/open. c#L228 — похоже, он был представлен в ядрах 2.6.38 и более поздних версиях. - person Mats Petersson; 28.12.2012
comment
posix_fallocate(3) glibc возвращается к поведению «чтение-затем-запись» только в том случае, если fallocate(2) не работает с EOPNOTSUPP, т.е. на фат32 фс или ауфс. Невозможно отключить резервное поведение в случае, когда вам нужна только подсказка по производительности, а не гарантия дискового пространства, без прямого использования fallocate(2) или fcntl, а не переносимого posix_fallocate(3). Не знаю, что делают реализации posix_fallocate в других системах (FreeBSD, OS X, Solaris?). См. мой ответ для некоторых ссылок, включая код, который проверяет наличие нескольких методов. - person Peter Cordes; 07.05.2014

По крайней мере, один бит информации взят из man-страницы fallocate(2):

int fallocate(int fd, int mode, off_t offset, off_t len);

DESCRIPTION
   This is a nonportable, Linux-specific system call.

Хотя в документации по системным вызовам об этом ничего не сказано, справочная страница программы fallocate(1) говорит:

As of the Linux Kernel v2.6.31, the fallocate system call is supported
by the btrfs, ext4, ocfs2, and xfs filesystems.

Для меня это имеет смысл, так как NTFS, FAT, CDFS и большинство других распространенных файловых систем не имеют внутреннего механизма на диске для поддержки вызова. Я предполагаю, что их поддержка будет буферизована ядром, и этот параметр не будет сохраняться при загрузке системы.

person wallyk    schedule 28.12.2012
comment
На самом деле Linux просто возвращает -1 с errno, установленным в ENOSYS, когда файловая система не поддерживает операцию. Это задокументировано, по крайней мере, в некоторых версиях справочной страницы. - person Nemo; 11.06.2015