SSD卡驱动中trim命令的实现原理
来源:互联网 发布:淘宝一天最多几个好评 编辑:程序博客网 时间:2024/06/05 10:52
有关trim命令的简介 可以看下http://blog.csdn.net/yuzhihui_no1/article/details/46519701
这里就大概的说下驱动中对trim命令的实现吧,由于对公司代码的保密性,这里就不沾贴代码了,就大概的说下实现原理;
条理会有点乱,也借此机会复习整理下一些相关知识点;
首先是块设备的基本框架:队列 queue和绑定队列的函数
先说说一般的块设备框架:
dev->queue = blk_init_queue(request, &dev->lock);
每个块设备都需要一个请求队列(后面会讲有的不需要队列),这是因为对块设备请求数据的传人和输出发生的时间,与内核请求的时间相差太大了,所以需要队列来对一些请求做处理。比如合并req、调整req的请求顺序之类的(后面有时间会注重分析io请求的合并和排序)。
从这里就可以看出,为什么要有队列?就是因为请求的传人和输出时间与内核的请求时间相差太大。反之,如果块设备请求数据的传入和传出时间,与内核请求的时间相差不大,是不是就意味着可以不用队列?
答案是肯定的,SSD的驱动就是不需要队列的。
原因:1、SSD设备的响应时间和请求时间相差不大(其实对CPU来说还是比较大的);
2、也是最主要的,或者说最本质的,最根本的,就是SSD是电子设备,而普通盘是机械设备。普通硬盘读写速度之所以慢的原因是机械臂的移动耗费的时间,所以就有电梯算法之类的,来减少机械臂的移动。而SSD卡是电子设备,不存在寻址(机械臂移动就是为了寻址)耗费时间,可以类比下内存,也可以类比下hash算法,或者再类比下查字典,其实原理大致一样的,不需要顺序的一个一个的去寻址;
介于上面的原因,就不需要对io请求进行排序,或者合并之类的(驱动中请求合并还是会有的,但不是因为寻址的原因,而是为了提高读性能,和内存管理中的预读页是一样的原理)
下面接着说普通块设备的队列和请求函数,当请求队列生成的时候,请求函数就已经和队列绑定了。而且还赠送了一个把自旋锁。当request()函数被调用时,这把锁会由内核来控制,也就是说request()函数是在原子上下文中运行的(所以定义request函数时,要牢记遵守原子上下文的规则)。
request()函数有自旋锁时,可以防止内核再给他安排其他的请求;request()函数内要开锁时,一定要记得先禁止其他线程对队列和包含数据的访问,而request()函数返回时,必须要得到该锁。
对普通块设备来说request()函数就承载了,设备的读写请求的处理了。在线程调用该函数返回前,不需要把所有的请求都执行完,但request函数必须有返回响应,而且还得保证能完成所有的请求;
接下来说说SSD驱动中使用的无请求队列的块设备框架:
首先还是自己创建一个队列:queue = blk_alloc_queue(GFP_NOIO);//该函数会告诉块设备子系统,驱动使用定制的make_request函数。该队列不保存请求;
然后还是绑定请求函数:blk_queue_make_request(queue, make_request);
最后是构造一个请求函数:make_request(q, bio);
从上层一直往下走的话,到block层会有__generic_make_request(struct bio *bio)函数,该函数有两行代码可以引出块设备驱动的运行;
q = bdev_get_queue(bio->bi_bdev);//从块设备结构体中获取到queue
ret = q->make_request_fn(q, bio);//开始执行队列绑定的处理函数了
现在来说说trim命令了,在驱动中首先会判断这个bio请求是否是丢弃的bio,看bio->bi_rw标识 ,如果是丢弃的,就是trim命令了。
接着就调用get_bi_sector(bio)来获取到bio->bi_sector第一个请求的sector,再根据bio->bi_size 来得到最后一个请求的sector,其中的一些对齐转换,根据不同需求再做决定。最后就是实际的丢弃操作了;
目前已经得到了要丢弃的数据范围,循环去执行丢弃操作,分析丢弃一个lba的动作,其他的循环丢弃就可以了;
丢弃一个lba动作:首先获取到ftl映射表中对应pba地址,如果是空的,表示该位置上实际就没有数据,那就不需要操作,直接返回;
如果lba对应的ftl映射表pba地址,已经存在,则修改映射表,使lba对应的pba为空,接着就需要把实际的pba(开始映射表对应的pba)设置为无效。各个驱动设计的不一样,但总的思路就是把pba标记为无效,然后再根据该pba所在的sb是什么状态,再做一些状态的调整和处理。
总之,最后就会把该sb从其他链表中拿出来,挂载到待擦除链表上,接着就会唤醒gc线程去做gc工作。而gc线程做的工作是搜索需要回收的sb,还有就是回收sb。从链表上的sb中去判断每个pba是否有效,如果有效就读取pba上的数据,然后再写入到新的地址上。一直循环,直到把sb上的所有有效的pba数据搬运完,然后就开始真正的擦除该sb,擦除后再把该sb挂到free_block链表上。
最后就调用下 bio_end(bio, bio->bi_size, 0)函数返回,trim命令就这么愉快的结束了,但后台gc线程还在跑。
转载地址:http://blog.csdn.net/yuzhihui_no1/article/details/51325360
- SSD卡驱动中trim命令的实现原理
- SSD卡驱动中trim命令的实现原理
- SSD固态硬盘的Trim命令是什么
- SSD TRIM原理详解
- MAC 快捷命令 实现SSD 开启 TRIM 支持
- SSD基础之Trim命令
- ubuntu开启SSD的Trim
- SSD Trim
- js中trim的实现
- SSD的工作原理、GC和TRIM、写入放大以及性能评测
- SSD固态硬盘的实现原理
- SSD的TRIM功能有什么作用
- javascript 中对Trim()的实现
- bash中trim函数的实现
- JavaScript中Trim(),TrimStart(),TrimEnd()的实现
- JavaScript中Trim(),TrimStart(),TrimEnd()的实现
- Objective-C中trim的实现
- js中trim函数的简单实现
- 在Python IDLE中实现清屏
- JAVA8学习笔记-Function
- 关于<c:if>没有<c:else>解决方案
- 分享一个仿微信多选图cordova插件(相册内带相机功能)
- 二分查找法
- SSD卡驱动中trim命令的实现原理
- Scrollview嵌套Recyclerview出现的显示不全 不显示问题的解决方法
- 数据库个人总结
- 神经网络入门之Logistic回归(分类问题)
- 写作建议
- 剑指offer--面试题7:重建二叉树
- css笔记:包含块(Containing Block)
- Java还要再学一遍基础(十五)
- 第一节 scala 变量的定义和使用