答案1
如果你想确保碎片但不防止它(所以你只能部分控制发生的事情),并且你不关心碎片的细节,这是一种快速而肮脏的做事方式。
要创建n
至少包含两个片段的块文件:
- 使用同步写入打开文件,写入 m < n 块。
- 打开另一个文件。添加到它,直到磁盘上最多有 n - m 块可用。不要错误地将其稀疏!
- 将剩余的 n - m 块写入第一个文件。
- 关闭
unlink
第二个文件。
您可以通过交错更多文件来分割更多片段。
这假设文件系统可用于此类折磨,即不在多用户或关键任务环境中。它还假设文件系统没有保留块,或者保留块是为您的 UID 保留的,或者您是 root。
没有直接的确保碎片的方式,因为 Unix 系统采用文件系统抽象,所以你永远不会与原始文件系统交谈。
此外,确保文件系统级碎片不会告诉您较低级别发生的情况。 LVM、软件和硬件 RAID、硬件级扇区重新映射和其他抽象层可能会对您的期望(和测量)造成严重破坏。
答案2
我还没有遇到过 Linux 上的通用文件系统会牺牲写入吞吐量而不是连续文件。也就是说,如果文件以非顺序顺序写入,则每个文件系统都会产生碎片,尤其是对于稀疏文件。
简单的方法:通过 torrent 客户端运行文件——最好是不预先分配文件的客户端。 BitTornado 或 rtorrent 符合这个要求。 (前者有可配置的分配模式)
困难的方法:将源文件分割成几KB大小的片段,然后对它们进行打乱。打开目标文件。对于每一篇文章,找到它的正确位置并写下来。
这是一个执行此操作的 Perl 脚本:
#!/usr/bin/perl
use List::Util qw/shuffle/;
use IO::Handle;
use constant BLOCK_SIZE => 4096;
my ($src, $dst) = @ARGV;
my $size = (stat($src))[7];
my @blocks = shuffle(0 .. ($size / BLOCK_SIZE));
my ($srcfh, $dstfh);
open $srcfh, "<", $src or die "cannot open $src: $!";
open $dstfh, ">", $dst or die "cannot open $dst: $!";
truncate $dstfh, $size; # undefined behaviour
my $buf;
for my $blockno (@blocks) {
seek $_, $blockno * BLOCK_SIZE, 0 for ($srcfh, $dstfh);
read $srcfh, $buf, BLOCK_SIZE;
print $dstfh $buf;
$dstfh->flush;
}
close $dstfh;
close $srcfh;
filefrag
您可以使用 e2fsprogs 包中包含的命令检查碎片。
以下是 torrent 的作用示例:
# ls -sh amd64memstick-5.1.2.fs.gz
239M amd64memstick-5.1.2.fs.gz
# filefrag amd64memstick-5.1.2.fs.gz
amd64memstick-5.1.2.fs.gz: 585 extents found
这是我的脚本(在 ext3 上)得到的结果:
$ ls -sh source.tar
42M source.tar
$ perl fragment.pl source.tar fragmented.tar
$ md5sum fragmented.tar source.tar
f77fdd7ab526ede434f416f9787fa9b3 fragmented.tar
f77fdd7ab526ede434f416f9787fa9b3 source.tar
# filefrag fragmented.tar
fragmented.tar: 395 extents found
编辑:没关系,除了较大的文件(肯定是 1.5 GB 的文件碎片)之外,它似乎根本无法正常工作。
VM 系统可能正在缓存并推迟/重新排序太小的写入。这就是为什么 torrent 客户端会设法产生碎片(因为它们通常不会以 >10MB/s 的速度下载),但我的脚本却不会。我认为可以通过降低虚拟机阈值来调整。看/proc/sys/vm/dirty_*