FIDEDUPERANGE ioctl 在 btrfs 上的行為不符合預期
的最大大小*
src_length
*取決於文件系統,通常為 16 MiB。但是,我已經能夠通過
src_length
一次呼叫成功使用 > 1 Gibioctl
。至少對於 16 MiB 的警告是否完全誇大了btrfs
?此外,根據VFS 文件,
實現必須處理傳入 len == 0; 的呼叫者;這意味著“重新映射到源文件的末尾”。
但是,當我嘗試設置
src_length
為0
時,ioctl
呼叫成功但不執行任何操作。我是誤讀了這兩句話,還是
btrfs
實現根本不符合(很好)文件?我正在使用 kernel 在 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); }
舊版本
btrfs
(例如,4.15)每次FIDEDUPERANGE
呼叫有 16 MiB 的限制,並且會默默地將超大請求減少到 16 MiB。我忘記了更改發生的確切時間,但目前版本btrfs
(即 5.16)以 16 MiB 塊循環。不過,我認為 linux(btrfs
現在不是)仍然默默地減少超過 1 GiB 的請求。如果您希望FIDEDUPERANGE
與舊版本一起使用btrfs
,您絕對應該遵守 16 MiB 的限制。此外,其他文件系統可能有類似的限制。至於
src_length = 0
,您應該真正查閱個人ioctl
s 的文件以獲取有關如何使用它們的說明。您正確引用的man
頁面FIDEDUPERANGE
文件src_length = 0
意味著沒有重複數據刪除。關於您引用的 VFS 頁面,事情很複雜。
remap_file_range()
處理ioctl
改編自btrfs
最初在 中單獨設計和實現的多個 s 的功能btrfs
。在 cloneioctl
中,src_length == 0
表示複製到文件末尾。在 dedupioctl
中,src_length == 0
意味著 dedup 什麼都沒有。我忘記了確切的時間,但有人努力統一複製和重複數據刪除功能。但是,更改ioctl
目前支持的btrfs
. 在 5.16 版中,有一個奇怪的 hack 涉及btrfs_remap_file_range_prep()
將len
參數轉換為remap_file_range()
取決於ioctl
是複製或重複數據刪除呼叫。很容易說 VFS 文件是錯誤的,因為我認為btrfs
這裡的行為沒有改變。但是,我不確定其他文件系統是否已經實現remap_file_range()
了這個含義len == 0
,所以它很複雜。