~によるとioctl_fideduperange、
最大サイズは
src_length
ファイルシステムによって異なりますが、通常16MiBです。
src_length
ただし、単一の呼び出しで1Gib以上を正常に使用できましたioctl
。少なくとも16MiBの警告は完全に誇張されていますかbtrfs
?
その上によるとVFSドキュメント、
実装では、len == 0で渡される呼び出し元を処理する必要があります。これは、「ソースファイルの末尾への再マッピング」を意味します。
ただし、に設定しようとすると呼び出しは成功src_length
しますが、何もしません。0
ioctl
私はこの2つの文を誤って読んでいますか?それとも、btrfs
実装が単に(非常に良い)文書に従わないのでしょうか?カーネルを使用してLinux Mint 20でテストしています5.4.0-62-generic
。私はそれを使用してfilefrag -sv FILE1 FILE2
ファイルのブロックレベルの割り当てを調べて、ファイルが重複していることを確認します。重複ファイルを削除するには、次のプログラムを使用しています。問題のファイルbtrfs
はsudo mkfs.btrfs -mraid1 -draid1 /dev/mapper/sda1_crypt /dev/mapper/sdb1_crypt
。
想像する:
$ cp -f file1 file2
$ filefrag -sv file1 file2 # see that files use different extents (are not deduplicated)
$ myprog file1 file2
$ filefrag -sv file1 file2 # see that files use the same extents (have been deduplicated)
両方のファイルから重複エントリを削除する手順:
// deduplicate srcfile and targetfile if contents are identical
// usage: myprog srcfile targetfile
// compile with: gcc myprog.c -o myprog
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
int main(int argc, char**argv)
{
struct stat st;
long size;
__u64 buf[2048]; /* __u64 for proper field alignment */
struct file_dedupe_range *range = (struct file_dedupe_range *)buf;
memset(range, 0, sizeof(struct file_dedupe_range));
memset(&range->info, 0, sizeof(struct file_dedupe_range_info));
long srcfd = open(argv[1], O_RDONLY);
if (srcfd < 0) { perror("open-src"); exit(1); }
if (fstat(srcfd, &st) < 0) { perror("stat-src"); exit(1); }
size = st.st_size;
long tgtfd = open(argv[2], O_RDWR);
if (tgtfd < 0) { perror("open-tgt"); exit(1); }
if (fstat(tgtfd, &st) < 0) { perror("stat-tgt"); exit(1); }
if (size != st.st_size) {
fprintf(stderr, "SIZE DIFF\n");
exit(1);
}
range->src_offset = 0;
range->src_length = size;
// range->src_length = 0; // I expected this to work
range->dest_count = 1;
range->info[0].dest_fd = tgtfd;
range->info[0].dest_offset = 0;
while (range->src_length > 0) {
if (ioctl(srcfd, FIDEDUPERANGE, range) < 0) { perror("ioctl"); exit(1); }
fprintf(stderr, "bytes_deduped: %llu\n", range->info[0].bytes_deduped);
fprintf(stderr, "status: %d\n", range->info[0].status);
if (range->info[0].status == FILE_DEDUPE_RANGE_DIFFERS) {
fprintf(stderr, "DIFFERS\n");
break;
} else if (range->info[0].status == FILE_DEDUPE_RANGE_SAME) {
fprintf(stderr, "SAME\n");
} else {
fprintf(stderr, "ERROR\n");
break;
}
if (range->info[0].bytes_deduped >= range->src_length) { break; }
range->src_length -= range->info[0].bytes_deduped;
range->src_offset += range->info[0].bytes_deduped;
range->info[0].dest_offset += range->info[0].bytes_deduped;
}
exit(0);
}
答え1
以前のバージョンbtrfs
(例:4.15)FIDEDUPERANGE
は呼び出しごとに16MiBに制限され、非常に大きな要求を自動的に16MiBに減らします。いつ変更が発生したかを正確に忘れましたが、現在のバージョンbtrfs
(例:5.16)は16MiBチャンク単位で循環します。しかし、私の考えでは、Linux(btrfs
今ではない)が依然として1GiB以上の要求を自動的に減らしているようです。FIDEDUPERANGE
以前のバージョンを使用するには、btrfs
16MiB制限に準拠する必要があります。また、他のファイルシステムにも同様の制限がある可能性があります。
それについては、使用方法についての指示については、src_length = 0
各個人の文書を参照する必要があります。ioctl
正しく参照しているページは、man
何も削除されないことを意味します。FIDEDUPERANGE
src_length = 0
あなたが参照したVFSページに関しては、状況は複雑です。元々個別に設計および実装された複数の項目で適用されたremap_file_range()
機能を処理します。 clone s は、ファイルの最後まで複製することを意味します。重複排除とは重複排除が行われないことを意味します。まさにいつであるかは覚えていませんが、複製と重複排除機能を統合する努力がありました。ただし、バージョン5.16では、複製呼び出しか重複排除呼び出しであるかに応じて、パラメータを変換する奇妙なハックがあります。ここでは動作が変わっていないと思うので、VFS文書が間違っていると言うのは簡単です。しかし、他のファイルシステムでこの意味を実装したかどうかはわかりません。ioctl
btrfs
btrfs
ioctl
src_length == 0
ioctl
src_length == 0
ioctl
btrfs
btrfs_remap_file_range_prep()
len
remap_file_range()
ioctl
btrfs
remap_file_range()
len == 0