从应用的视角,iscsi展现为一个块设备,即一块硬盘。在Linux操作系统中可以通过fdisk -l看到这块磁盘。iscsi协议所涉及的一系列的组件经过层层虚拟化,在多个层次上其操作与本地硬盘无异。这实际上是一个性能、可靠性、实现多个角度权衡的结果。事实上,在所经历的各层次中,有一些次层对于iscsi磁盘来说是多余的,但操作系统的设计者为了共用SCSI实现层,将scsi initiator对接到SCSI中间层以下,作为一个scsi传输层实现。因此,自scsi层以上,iscsi提供的块设备与sas、SATA提供的块设备所经历的IO流转一致。

本文所涉及的iscsi集中考虑iscsi协议承接块设备应用说起。事实上,iscsi作为一个承载SCSI协议的传输层,除能够支持基于磁盘价值的块设备外,还可以支持其他的SCSI设备。比如磁 带、CDROM。业界也有通过iscsi实现为磁带的应用,如VTL。虚拟为其他设备时,其IO流转略有区别。scsi子系统通过INQUIRY探测LUN的设备类型,进而由上层驱动“认领”对应的设备。

用户的数据在initiator节点上依次经过文件系统层、块设备层、SCSI层。理论上我们也可以将通过裸scsi设备直接发送IO相关SCSI指令到SCSI中间层,但这条路径的初衷并非如此,没有针对IO处理进行优化。故只在上图中表示出来,并不做具体分析。
文件系统、裸设备在应用角度,其一般流程均为:
- 打开文件,获得句柄(系统调用open
- 一次或多次以字节为单位对文件进行读写(系统调用readwrite
- 关闭文件(系统调用close)

应用的IO请求通过系统调用到达内存。在适合当的时机,操作系统会将上述操作构建为bio结构,调用submit_bio将请求传递到通用块层。bio是通用块核心的IO处理单元。bio核心表达的是数据在内存和在磁盘中的映射关系。其中,
缓存中的地址以内存页号和页面偏移表示。以struct bio_vec表达:

struct bio_vec {struct page    *bv_page;   /*存储数据的页面*/unsigned int    bv_len;     /*数据长度*/unsigned int    bv_offset; /*数据在页面中的偏移*/
};

在磁盘上的地址以bvec_iter表达:

struct bvec_iter {sector_t            bi_sector;    /* device address in 512 byte sectors */unsigned int     bi_size;    /* residual I/O count */unsigned int     bi_idx;        /* current index into bvl_vec */unsigned int     bi_done;    /* number of bytes completed */unsigned int     bi_bvec_done;    /* number of bytes completed in current bvec */
};

在新的内核版本中,对bio数据结构进行了一些调整。老的版本中扇区号、扇区数等信息直接放在bio成员中。新的版本中将其集中放到bev_iter中。此变化不影响bio在设计中的位置

submit_bio最终调用generic_make_request函数将bio插入到请求队列。generic_make_request接收一个bio组成的链表,并对其进行分个处理。对于每个bio首先进行一系列应用的检查,然后调用具体块磁盘驱动的make_request_fn进行处理。scsi磁盘驱动初始化的过程中,将make_request_fn直接指定为blk_queue_bio。这个函数根据内核配置的IO电梯算法,将IO拆分合并到请求队列中。
上述的故事就是大家耳熟能祥的IO缓存与IO调度。在此不详细描述。可以参考其他资料研究buffer cache以及电梯调度算法相关的算法。转到iscsi实现的角度。initiator的处理过程并不需要电梯算法。毕竟到目前为止,我们数据离落盘还有很远很远。况且系统数据落盘是在target端进行,在initiator端进行电梯算法意义不大,target端有可能对数据进行重新散列,当下排序也用的LBA还需要经过再次映射,逻辑上相邻不代表物理是想邻。
还是那句话,在iscsi流程过程中,之所以将这些流程纳入,完全是一种设计的权衡、抽象的哲学问题。
我们的故事刚刚开始。
自sd设备驱动开始,便进入SCSI处理的流程。也即iscsi相关语境的上下文。从此刻,系统要回答的问题有以下几方面:
1. IO如何封装成scsi指令,封装成什么样的scsi指令
2. IO如何根据设备的特点构建任务,经过协议所定义的host、taget、lun等相应的处理
3. IO处理过程中的异常采用什么方式,以什么形式报告给initiator等

sd实现了一个块设备(drivers/scsi/sd.c)用以接受IO请求,并最终调用scsi_setup_fs_cmnd将请求向scsi_cmd转换,进而分发到scsi中间层进行处理。scsi中间层可以理解为SCSI处理的一个框架实现,提供了SCSI系统初始化、设备扫描、SCSI命令调度执行以及错误恢复框架等。从IO角度,SCSI中间层主要是接受IO相关的SCSI指令,进一步完善相应用的信息,调用scsi_dispatch_cmd传递到下层进行处理。
最终的scsi指令的执行是在target端进行。scsi transport层是负责SCSI指令传输的,像SAS、FC、iscsi等都是传输层的具体实现。传输层有对应的协议实现,其核心实现思路是scsi请求进行的封装。上述的SCSI命令只是scsi请求的一个方面,除此之外还有目的LUN、任务管理、数据等信息,具体信息可参考SAM相关文档。一个SCSI的具体执行可以形式性的表达为:

Service Response =Execute Command (IN ( I_T_L_Q Nexus, CDB, Task Attribute, [Data-In Buffer Size],
[Data-Out Buffer], [Data-Out Buffer Size], [Command Reference Number], [Task
Priority]), OUT ( [Data-In Buffer], [Sense Data], [Sense Data Length], Status ))

一个SCSI指令相关的请求在传输层被称为一个task(任务),当SCSI命令被发送到scsi传输协议服务系统时,任务被建立。任务用于管理SCSI在传输层流转的一系列状态信息。当SCSI target返回响应之后task重命周期完成。一个传输任务可分为一个或者多个数据包传输给target。在iscsi协议中用PDU表示每个数据包。iscsi协议是scsi传输层的具体实现,它实现的了initiator与target间的认证、会话建立、数据联接管理、数据传输、任务控制、数据安全等一系列的服务。iscsi采用PDU描述传输数据包,是iscsi层各节点间交互的基本单位,iscsi协议是scsi传输层的具体实现。iscsi PDU将使TCP协议或者其它流式协议进行传输。在Linux系统中实现了iscsi_tcpiscsi_iser两个传输模块。

以上就是Linux内核中iscsi协议initiator端实现的具体流程,流转过程中,一个IO请求自上而下经历了biorequestscsi_cmdiscsi_task以及iscsi hdr(PDU)等变化。

思考:
本文提到为了系统实现概念的统一性、设计的一致性以及层次抽象与共用,操作系统将iscsi协议对接到scsi中间层。这种实现对性能的损失有多大?如果我们在device-mapper之下实现又会怎么样?欢迎讨论。

iscsi:IO操作流程(一)相关推荐

  1. iscsi:IO操作流程(四)

    系统构建SCSI指令后,将调用scsi_host的queucommand操作,将指令下移到LLD设备层进行处理. scsi_host在iscsi协议中的角色 scsi_host在系统中启动承上启下的作 ...

  2. iscsi:IO操作流程(五)——IO完成处理

    概述 前面讲到,iscsi initiator实现过程采用了多级的异步模式,通过异步模式使IO操作阶段能够批量处理.这种异步机制的存在主要为了提升系统的吞吐量.从设计的角度,考虑采用异步操作机制的任务 ...

  3. iscsi:IO操作流程(二)

    上次我们讨论了iscsi initiator IO操作需要经过的各个层次,以及每层所涉及的IO数据结构的变化.今天主要讨论IO如何形成SCSI指令并下发的. 我们知道在通用块层,IO最终放在reque ...

  4. iscsi:IO操作流程(三)

    概述 当我们讲到scsi命令这个概念时,需要根据上下文去理解.可能指代两个概念: - 一种含义指SCSI协议规划中定义的SCSI 命令描述块(Command descriptor block (CDB ...

  5. 网易数帆开源iSCSI服务器tgt独门优化,彻底解决性能问题

    iSCSI是现代企业级存储系统中的一项重要技术, 开源iSCSI 服务器tgt存在单线程性能问题,而相关的优化补丁效果参差不齐,尚未真正解决问题,本文介绍网易数帆存储团队如何通过一系列独特的创新实现t ...

  6. 【死磕NIO】— 阻塞IO,非阻塞IO,IO复用,信号驱动IO,异步IO,这你真的分的清楚吗?

    通过上篇文章([死磕NIO]- 阻塞.非阻塞.同步.异步,傻傻分不清楚),我想你应该能够区分了什么是阻塞.非阻塞.异步.非异步了,这篇文章我们来彻底弄清楚什么是阻塞IO,非阻塞IO,IO复用,信号驱动 ...

  7. 【翻译】QEMU内部机制:顶层概览

    系列文章: [翻译]QEMU内部机制:宏观架构和线程模型 [翻译]QEMU内部机制:vhost的架构 [翻译]QEMU内部机制:顶层概览(本文) [翻译]QEMU内部机制:内存 原文地址:http:/ ...

  8. java程序课程总结_java课程总结

    课程总结 一个学期结束了,下面我对一些重点知识分三个模块做一个小的总结. 一.Java基础程序设计 1.java中源文件的扩展名为.java,之后通过编译是.java的文件生成一个.class文件. ...

  9. java NIO入门小记

    传统的IO模式 传统的IO流是阻塞式的,会一直监听一个ServerSocket,在调用read等方法时,他会一直等到数据到来或者缓冲区已满时才返回.调用accept也是一直阻塞到有客户端连接才会返回. ...

最新文章

  1. 基于python的大数据分析实战学习笔记-pandas(数据分析包)
  2. 使用struts 2 获取服务器数据 ongl表达式 标签
  3. 201621123023《Java程序设计》第7周学习总结
  4. 配置php.ini文件,关闭错误提示,打开错误日志,设置错误日志路径(亲测)
  5. python如何计算分子描述符_Python——描述符(descriptor)解密
  6. 学习笔记之四_Cisco系统IOS和安全设备管理系统SDM(CCNA知识考点)
  7. H5 使用微信开放标签跳转小程序
  8. scala(10)-----Scala 闭包
  9. 电流感应电阻器行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)
  10. 极简Markdown程序员简历模板
  11. 黑客使用浏览器中的浏览器技术窃取Steam凭证
  12. 攻防世界题库logmein
  13. 德赛西威Mib280D升级0393版本系统
  14. 【论文笔记】Learning Convolutional Networks for Content-weighted Image Compression
  15. doodoo.js快速入门教程
  16. 火车票订票小助手,帮助了很多同事和朋友,安全无毒
  17. java_vinson_02:jdk下载安装
  18. 文本生成视频Make-A-Video,根据一句话就能一键生成视频 Meta新AI模型
  19. 【无标题】汇编实现从键盘输入并输出
  20. PostgreSQL 技术文档

热门文章

  1. Xcode 静态库调试策略
  2. WEB-INF/views/menu/list.jsp (line: 26, column: 58) equal symbol expected
  3. 华中邀请赛现场赛F题 Seats
  4. 微型计算机的主要,微型计算机组成,微型计算机主要由什么组成
  5. c语言CString转数字函数,CString与16进制的CByteArray之间相互转化
  6. python数字类型及运算_Python数据类型之数字(Numbers)和运算符
  7. qbittorrent container 改共享文件_SSH连接docker中的container
  8. Python批量检查docx文档中文本框的内容是否正确
  9. C++ STL容器之string--常用接口
  10. Python字符串的替换