10

posix_fallocateとの間でどの関数を使用するかについて議論していますfallocateposix_fallocateすぐにファイルを書き込みます(文字をNULLに初期化します)。ただし、fallocateファイルサイズは変更されません(FALLOC_FL_KEEP_SIZEフラグを使用する場合)。私の実験によるとfallocate、ファイルにNULLまたはゼロ文字を書き込まないようです。

誰かがあなたの経験に基づいてコメントできますか?御時間ありがとうございます。

4

3 に答える 3

6

表示された長さよりも多くのストレージ スペースを占有するファイルを持つことは一般的ではないため、そうする正当な理由がない限り (たとえば、ファイルの長さを使用して、ダウンロードがどこまで到達したかを追跡し、再開する目的で使用する場合)デフォルトの fallocate(2) 動作を使用するのが最善です。(FALLOC_FL_KEEP_SIZE なし)。これは posix_fallocate(3) と同じセマンティクスです。

fallocate(2) のマニュアル ページでは、そのデフォルトの動作 (フラグなし) は posix_fallocate(3) を実装する最適な方法として意図されており、スペースを割り当てる移植可能な方法としてそれを指し示しています。

元の質問は、ファイルにゼロを書き込むことについて何か言っています。これらの呼び出しでは、メタデータ以外は何も書き込まれません。事前に割り当てられているがまだ書き込まれていない領域から読み取ると、ゼロが返されます (以前にそのディスク領域にあったものではなく、大きなセキュリティ ホールになります)。ファイルの末尾 (fallocate、ftruncate、またはその他のさまざまな方法で設定された長さ) までしか読み取ることができないため、長さがゼロのファイルがあり、FALLOC_FL_KEEP_SIZE を使用して fallocate すると、何も読み取ることができません。ファイルサイズのセマンティクスだけで、事前割り当てとは関係ありません。

したがって、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)                           = ?

fat32 フラッシュ ドライブの場合:

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 の man ページがあり、POSIX で指定されているため、すべての POSIX 準拠システムで提供されています。1 つの欠点は、事前割り当てをサポートしていないファイルシステムで glibc を使用すると恐ろしいことです。たとえば、https://plus.google.com/+AaronSeigo/posts/FGtXM13QuhQを参照してください。大きなファイル (トレントなど) を扱うプログラムの場合、これは非常に悪いことです。

「ファイルシステムは事前割り当てをサポートしていません」というエラーコードを定義していないため、これを行うために glibc を必要とする POSIX セマンティクスに感謝できます。 http://pubs.opengroup.org/onlinepubs/009695399/functions/posix_fallocate.html . また、呼び出しが成功した場合、割り当てられた領域への後続の書き込みがディスク容量不足のために失敗しないことも保証されます。そのため、posix 設計では、呼び出し側がディスク容量の保証ではなく、効率/パフォーマンス/断片化を気にするケースを処理する方法が提供されません。これにより、POSIX 実装は、ディスク領域の保証が必要な呼び出し側のオプションとしてそれを残すのではなく、読み書きループを実行するように強制されます。ありがとうPOSIX...

ファイルシステムが事前割り当てをサポートしていない場合、posix_fallocate の非 GNU 実装が同様に非常に遅い読み取り/書き込み動作にフォールバックするかどうかはわかりません。(FreeBSD、Solaris?)。どうやら OS X (Darwin) は、ごく最近でない限り、posix_fallocate を実装していないようです。

多くのプラットフォームで事前割り当てをサポートすることを検討しているが、OS に事前割り当てを試行する方法がある場合に読み取り後書き込みにフォールバックしない場合は、利用可能なプラットフォーム固有の方法を使用する必要があります。たとえば、 https://github.com/arvidn/libtorrent/blob/master/src/file.cppを確認してください。

file::set_size を検索します。コンパイル ターゲットがサポートするものに応じて、いくつかの ifdefed ブロックがあり、DLL をロードしてそこで何かを実行する Windows コードから始まり、次に fcntl F_PREALLOCATE、または fcntl F_ALLOCSP64、次に Linux fallocate(2)、そして posix_fallocate の使用にフォールバックします。また、OS X Darwin に関するこの 2007 年のリスト投稿を見つけました: http://lists.apple.com/archives/darwin-dev/2007/Dec/msg00040.html

于 2014-05-07T04:24:53.477 に答える
4

私はあなたが言うドキュメントを見ていないと思います

   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() のマニュアルページには同じことが言及されていないようですが、代わりに、ソースhereを見ると、ファイルの各ブロックが書き込まれているようです (88 行目)。

man fallocate man posix_fallocate

于 2012-12-28T00:40:16.823 に答える
2

少なくとも 1 ビットの情報は、fallocate(2) の man ページからのものです。

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、および他のほとんどの一般的なファイル システムには、呼び出しをサポートするためのディスク上の内部メカニズムがないため、これは私には理にかなっています。それらのサポートはカーネルによってバッファリングされ、システムの起動後は設定が保持されないと思います。

于 2012-12-28T00:31:30.553 に答える