数码之家

 找回密码
 立即注册
搜索
查看: 3622|回复: 25

[Other] 关于固态存储设备TRIM功能的一些研究

[复制链接]
发表于 2024-1-7 21:32:22 来自手机浏览器 | 显示全部楼层 |阅读模式

爱科技、爱创意、爱折腾、爱极致,我们都是技术控

您需要 登录 才可以下载或查看,没有账号?立即注册

x
好久没发帖了,上号发现M币都给我扣成负数,还是发个贴赚点币吧
这里简单说说我对TRIM机制的研究,大伙随便看看,如果有哪里不对也请指出来。
下面这段是复制我博客的:

Trim是固态硬盘中的一种垃圾回收机制。百度上的废话这里就不复制粘贴了,说一说笔者的理解:
操作系统向固态硬盘发起Trim命令,将文件系统中无用块的信息发送给固态硬盘主控,主控收到命令后会在空闲时对无用块进行擦除。由于SSD的特性,如果一块空间中有垃圾数据,想要写新的数据进去就必须将垃圾数据先擦除后写入,经常进行Trim操作理论上可以改善磁盘的读写性能。
目前已知Windows和Linux都支持固态硬盘的Trim操作。

然后,由于Windows不开源嘛,就只能基于开源的Linux研究了
通过查看内核源码(6.1)中的文件系统相关驱动,以下文件系统支持Trim:
ext4、btrfs、ecryptfs、f2fs、fat、gfs2、hpfs、jfs、nilfs2、ntfs3、exfat、ocfs2、xfs

Linux下TRIM很简单,使用util-linux包中的fstrim工具即可:
  1. sudo fstrim -av
  2. /var/log: 137.7 MiB (144424960 bytes) trimmed on /dev/zram1
  3. /boot: 912.2 MiB (956493824 bytes) trimmed on /dev/mmcblk0p1
  4. /: 1.6 GiB (1746763776 bytes) trimmed on /dev/mmcblk0p2
复制代码

然后,楼下简单追一下Trim的实现:

打赏

参与人数 2家元 +96 收起 理由
perter + 6 原創內容
家睦 + 90

查看全部打赏

 楼主| 发表于 2024-1-7 21:36:04 | 显示全部楼层
先看fstrim源码:
  1. if (ioctl(fd, FITRIM, &range)) {
  2. switch (errno) {
  3. case EBADF:
  4. case ENOTTY:
  5. case EOPNOTSUPP:
  6. case ENOSYS:
  7. rc = 1;
  8. break;
  9. default:
  10. rc = -errno;
  11. }
  12. if (rc < 0)
  13. warn(_("%s: FITRIM ioctl failed"), path);
  14. goto done;
  15. }
复制代码


这里ioctl发送的是FITRIM命令,参数是一个结构体range:
  1. // /usr/include/linux/fs.h
  2. struct fstrim_range {
  3. __u64 start;
  4. __u64 len;
  5. __u64 minlen;
  6. };
复制代码

而在结构体传入之前,main函数已经将len设置为一个很大的值:
  1. struct fstrim_control ctl = {
  2. .range = { .len = ULLONG_MAX } // 真的很大
  3. };
复制代码


ioctl完成后,打印已经trim的字节数量的代码:
  1. if (ctl->verbose) {
  2. char *str = size_to_human_string(
  3. SIZE_SUFFIX_3LETTER | SIZE_SUFFIX_SPACE,
  4. (uint64_t) range.len);
  5. if (devname)
  6. /* TRANSLATORS: The standard value here is a very large number. */
  7. printf(_("%s: %s (%" PRIu64 " bytes) trimmed on %s\n"),
  8. path, str, (uint64_t) range.len, devname);
  9. else
  10. /* TRANSLATORS: The standard value here is a very large number. */
  11. printf(_("%s: %s (%" PRIu64 " bytes) trimmed\n"),
  12. path, str, (uint64_t) range.len);

  13. free(str);
  14. }
复制代码


熟悉Linux的朋友知道,ioctl是和内核交互了,所以要追溯到内核层了。这里简单追一下ext4的实现:
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-1-8 08:15:39 | 显示全部楼层

关于固态存储设备TRIM功能的一些研究

  1. /**
复制代码
  1. * ext4_trim_fs() -- trim ioctl handle function
  2. * @sb: superblock for filesystem
  3. * @range: fstrim_range structure
  4. *
  5. * start: First Byte to trim
  6. * len: number of Bytes to trim from start
  7. * minlen: minimum extent length in Bytes
  8. * ext4_trim_fs goes through all allocation groups containing Bytes from
  9. * start to start+len. For each such a group ext4_trim_all_free function
  10. * is invoked to trim all free space.
  11. */
  12. int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range);
复制代码
有注释省得看代码了内核将指定(len)文件系统的区域进行了扫描,并且调用ext4_trim_all_free函数:
  1. /**
  2. * ext4_trim_all_free -- function to trim all free space in alloc. group
  3. * @sb: super block for file system
  4. * @group: group to be trimmed
  5. * @start: first group block to examine
  6. * @max: last group block to examine
  7. * @minblocks: minimum extent block count
  8. *
  9. * ext4_trim_all_free walks through group's buddy bitmap searching for free
  10. * extents. When the free block is found, ext4_trim_extent is called to TRIM
  11. * the extent.
  12. *
  13. *
  14. * ext4_trim_all_free walks through group's block bitmap searching for free
  15. * extents. When the free extent is found, mark it as used in group buddy
  16. * bitmap. Then issue a TRIM command on this extent and free the extent in
  17. * the group buddy bitmap. This is done until whole group is scanned.
  18. */
  19. static ext4_grpblk_t
  20. ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
  21. ext4_grpblk_t start, ext4_grpblk_t max,
  22. ext4_grpblk_t minblocks);
复制代码
文件系统将无用块标记,然后向磁盘发送trim命令来清除这些块的数据。楼主是mmc设备,所以追溯到mmc设备的驱动实现:
  1. static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
  2. {
  3. struct mmc_blk_data *md = mq->blkdata;
  4. struct mmc_card *card = md->queue.card;
  5. unsigned int from, nr;
  6. int err = 0, type = MMC_BLK_DISCARD;
  7. blk_status_t status = BLK_STS_OK;

  8. if (!mmc_can_erase(card)) {
  9. status = BLK_STS_NOTSUPP;
  10. goto fail;
  11. }

  12. from = blk_rq_pos(req);
  13. nr = blk_rq_sectors(req);

  14. do {
  15. unsigned int erase_arg = card->erase_arg;

  16. if (mmc_card_broken_sd_discard(card))
  17. erase_arg = SD_ERASE_ARG;

  18. err = 0;
  19. if (card->quirks & MMC_QUIRK_INAND_CMD38) {
  20. err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
  21. INAND_CMD38_ARG_EXT_CSD,
  22. card->erase_arg == MMC_TRIM_ARG ?
  23. INAND_CMD38_ARG_TRIM :
  24. INAND_CMD38_ARG_ERASE,
  25. card->ext_csd.generic_cmd6_time);
  26. }
  27. if (!err)
  28. err = mmc_erase(card, from, nr, erase_arg);
  29. } while (err == -EIO && !mmc_blk_reset(md, card->host, type));
  30. if (err)
  31. status = BLK_STS_IOERR;
  32. else
  33. mmc_blk_reset_success(md, type);
  34. fail:
  35. blk_mq_end_request(req, status);
  36. }
复制代码
这里就可以发现是发送了INAND_CMD38_ARG_TRIM或者是INAND_CMD38_ARG_ERASE命令给mmc设备,然后mmc进入内置固件的TRIM处理逻辑。而固件这玩意儿又没有源码,所以最多只能追溯到这里了。

然后简单验证一下TRIM:
先随便搞一个二进制文件:
  1. dd if=/dev/urandom of=test.bin bs=1 count=16
  2. 输入了 16+0 块记录
  3. 输出了 16+0 块记录
  4. 16 字节已复制,0.000342409 s,46.7 kB/s
复制代码

生成了一个test.bin,用hexdump看一看内容:
  1. hexdump -C test.bin
  2. 00000000 3c 73 d1 0e 6f 23 54 d1 6d 51 68 88 c3 24 26 49 |<s..o#T.mQh..$&I|
  3. 00000010
复制代码
  1. sudo hdparm --fibmap test.bin
  2. test.bin:
  3. filesystem blocksize 4096, begins at LBA 2158592; assuming 512 byte sectors.
  4. byte_offset begin_LBA end_LBA sectors
  5. 0 6815240 6815247 8
复制代码
  1. hexdump -C --skip 3489402880 --length 16 /dev/mmcblk0
  2. cffc1000 3c 73 d1 0e 6f 23 54 d1 6d 51 68 88 c3 24 26 49 |<s..o#T.mQh..$&I|
  3. cffc1010
复制代码

再次使用hexdump读取相应位置的数据:
  1. hexdump -C --skip 3489402880 --length 16 /dev/mmcblk0
  2. cffc1000 3c 73 d1 0e 6f 23 54 d1 6d 51 68 88 c3 24 26 49 |<s..o#T.mQh..$&I|
  3. cffc1010
复制代码

可以看见,数据还在原位。大概是因为mmc设备的原因吧,我用手机测试,两小时就把删掉的文件块给TRIM了。
欢迎大家探讨

回复 支持 1 反对 0

使用道具 举报

发表于 2024-1-8 09:32:08 | 显示全部楼层
给楼主加分
回复 支持 1 反对 0

使用道具 举报

发表于 2024-1-8 10:58:18 | 显示全部楼层
看不太懂,也给楼主加分!
回复 支持 1 反对 0

使用道具 举报

发表于 2024-1-8 21:59:03 来自手机浏览器 | 显示全部楼层
win7下USB似乎没有TRIM,我ASM1153E和JMS578已经刷了支持UASP和TRIM的固件,系统也打了uasp补丁,但是用工具测试下来总是TRIM APPEAR TO BE NOT WORKING……
回复 支持 1 反对 0

使用道具 举报

发表于 2024-1-9 10:38:31 | 显示全部楼层
此处想艾特一下dongfangw 希望他发表一下意见  想听听他的更高的见解
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2024-1-9 20:18:11 来自手机浏览器 | 显示全部楼层
yongjie 发表于 2024-1-9 10:38
此处想艾特一下dongfangw 希望他发表一下意见  想听听他的更高的见解

这哥们咋了
回复 支持 反对

使用道具 举报

发表于 2024-1-13 22:49:31 | 显示全部楼层
楼主牛人,底层原理也研究得明明白白,真的很厉害。7楼说的那个人我不好评价,
回复 支持 1 反对 0

使用道具 举报

发表于 2024-1-17 11:19:08 | 显示全部楼层
看不懂,有点深奥了。
回复 支持 1 反对 0

使用道具 举报

发表于 2024-1-20 21:52:23 | 显示全部楼层
给楼主加分
回复 支持 1 反对 0

使用道具 举报

发表于 2024-1-21 10:00:22 | 显示全部楼层
lz这可以拿高薪了吧
回复 支持 1 反对 0

使用道具 举报

发表于 2024-1-21 15:00:38 | 显示全部楼层
给楼主点个赞,你这分析的应该是手动trim,现在SSD都支持CG+trim了,你不用管,很多主控做CG的时候就自行trim了
回复 支持 1 反对 0

使用道具 举报

发表于 2024-1-21 15:06:20 | 显示全部楼层

那就是个有点技术的神棍
回复 支持 1 反对 0

使用道具 举报

发表于 2024-1-21 16:03:34 来自手机浏览器 | 显示全部楼层
perter 发表于 2024-1-21 15:00
给楼主点个赞,你这分析的应该是手动trim,现在SSD都支持CG+trim了,你不用管,很多主控做CG的时候就自行tr ...

常见的46 58 59主控支持自动trim吗
回复 支持 1 反对 0

使用道具 举报

发表于 2024-1-21 18:58:43 | 显示全部楼层
593323292 发表于 2024-1-21 16:03
常见的46 58 59主控支持自动trim吗

当然支持。。。。紫薯补丁
回复 支持 1 反对 0

使用道具 举报

发表于 2024-1-22 10:11:46 | 显示全部楼层
专业,建议不要给杂牌固态做磁盘清理,教训深刻
回复 支持 1 反对 0

使用道具 举报

发表于 2024-1-22 20:31:52 | 显示全部楼层
太深奥了,感谢楼主
回复 支持 1 反对 0

使用道具 举报

发表于 2024-1-23 00:10:53 | 显示全部楼层
Windows XP不支持TRIM,可惜了,以后的系统都支持的。LZ也研究下
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2024-1-23 14:09:16 来自手机浏览器 | 显示全部楼层
perter 发表于 2024-1-21 15:00
给楼主点个赞,你这分析的应该是手动trim,现在SSD都支持CG+trim了,你不用管,很多主控做CG的时候就自行tr ...

大部分Linux系统都带一个叫fstrim.timer的服务,启用之后会每周定期执行我上面说的那个trim命令。。。其实我也很好奇这个自动trim,按理说(ext4)删掉文件实际上就是从某个块的inode节点上删掉了文件索引,需要支持自动trim的话那么那套固件里面就得做一个可以解析ext4 inode结构的实现。。。世界上这么多文件系统,岂不是fat fat32 exfat ntfs这些都得做好对应的数据结构解析实现放在固件里面。。。不大可能

我个人认为只靠磁盘里的固件是没办法实现自动trim的,因为固件不知道在nand flash里面文件系统的数据结构,所以没有办法自动清理无用块。然后像Windows那种碎片检查机制,我估计是操作系统闲了没事就把文件系统扫一遍(或者是每次删除的时候实际上在某个区域里面存了这个文件的信息),扫出无用块之后把这些信息发给SSD,SSD接收到之后再找时机进行擦除操作。

以上观点均为猜测哈,毕竟我也没有Windows源码 :lol:
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2025-5-1 16:27 , Processed in 0.218400 second(s), 12 queries , Redis On.

Powered by Discuz!

© 2006-2025 MyDigit.Net

快速回复 返回顶部 返回列表