源文件
util-linux-<version>/sys-utils/fstrim.c
linux/fs/btrfs/ioctl.c
linux/fs/btrfs/extent-tree.c
linux/fs/btrfs/free-space-cache.c
用戶態工具 fstrim
fstrim 是 util-linux 軟件包中提供的工具:
discard unused blocks on a mounted filesystem
該工具有 3 個選項跟要 discard 的范圍有關:
-o, --offset offset Byte offset in filesystem from which to begin searching for free blocks to discard. Default value is zero, starting at the beginning of the filesystem. -l, --length length Number of bytes after starting point to search for free blocks to dis‐ card. If the specified value extends past the end of the filesystem, fstrim will stop at the filesystem size boundary. Default value extends to the end of the filesystem. -m, --minimum minimum-free-extent Minimum contiguous free range to discard, in bytes. (This value is inter‐ nally rounded up to a multiple of the filesystem block size). Free ranges smaller than this will be ignored. By increasing this value, the fstrim operation will complete more quickly for filesystems with badly fragmented freespace, although not all blocks will be discarded. Default value is zero, discard every free block.
查看 fstrim.c 的源文件,可以看到,fstrim 將 3 個范圍參數封裝到結構 struct fstrim_range 中,
struct fstrim_range { uint64_t start; uint64_t len; uint64_t minlen; };
然后通過 ioctl 命令 FITRIM 來完成實際的 discard 操作:
ioctl(fd, FITRIM, &range)
ioctl 接收 FITRIM 命令
btrfs/ioctl.c 對 FITRIM 命令進行處理:
case FITRIM: return btrfs_ioctl_fitrim(file, argp);
ioctl.c 文件中也定義了函數 btrfs_ioctl_fitrim,該函數對參數進行檢驗調整后(比如調整 minlen 為文件系統設備所支持的最小 discard 粒度,如果這個粒度比命令指定的 minlen 小的話,調整范圍不會超出文件末尾),轉而由 btrfs_trim_fs(fs_info->tree_root, &range) 來完成實際的工作。
btrfs_trim_fs 在 extent-tree.c 中定義,其工作就是從指定的起始地址對應的 block group 開始,對指定范圍內所覆蓋的 bg,逐個執行btrfs_trim_block_group。這就是工作的分解:
fstrim 整個文件系統 -> 逐個 trim 文件系統內的塊組
btrfs_trim_block_group 實現在 free-space-cache.c 中。
btrfs_trim_block_group
int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group, u64 *trimmed, u64 start, u64 end, u64 minlen) { int ret; *trimmed = 0; ret = trim_no_bitmap(block_group, trimmed, start, end, minlen); if (ret) return ret; ret = trim_bitmaps(block_group, trimmed, start, end, minlen); return ret; }
可以看出,trim bg 實際上是對 bg 下面的 extent/bitmap 空閑空間記錄進行 trim。
trim_no_bitmap 和 trim_bitmaps 都會調用 btrfs_error_discard_extent,而 btrfs_error_discard_extent 是對 btrfs_discard_extent 的簡單封裝。btrfs_discard_extent 會調用 btrfs_issue_discard,最終調用 blkdev_issue_discard 向塊設備發送 Discard/TRIM 命令。
對於 free-space-cache 來說,trim 就是把對應的空閑空間記錄給銷毀。
小結
fstrim 的執行流程:
fstrim -> FITRIM -> btrfs_ioctl_fitrim -> btrfs_trim_fs -> btrfs_trim_block_group -> trim_no_bitmap / trim_bitmaps -> btrfs_error_discard_extent -> btrfs_discard_extent -> btrfs_issue_discard -> blkdev_issue_discard