iscsi阶段性总结

时间:2021-07-14 00:28:05

iscsi的主干函数是以下的六个:
一:Iscsi 入口函数:static int __init iscsi_target_init_module(void)(iscsi_target.c:470)
二:Iscsi退出函数:static void __exit iscsi_target_cleanup_module(void)(iscsi_target.c:571)
三:Iscsi target注册函数 iscsi_target_register_configfs();(iscsi_target.c:486)
四:Iscsi接收线程:iscsi_target_rx_thread(iscsi_target.c:3753)
五:Iscsi发送线程:iscsi_target_tx_thread(iscsi_target.c:3702)
围绕着主干函数,这些主干的函数会调用很多函数以实现iscsi的功能,这些被调用的函数,有解析pdu的,对解析出来的pdu进行分类的,有对解析的pdu进行下发到底层的等等,在主干的函数下,大致记录这些被调用函数的作用,位置,方便以后查阅,具体详细的细节性问题,在另一篇中做了部分的记录,全是个人的理解加上添加打印,以及查阅资料,或者调试之后的结果。

三:iscsi_target_register_configfs();调用了一大堆的函数,主要实现的是:设置api函数指针指向,根据iscsi temple初始化fabric_iscsi,对fabric中的“发现”属性设置、tpg系列的属性设置,有“登录线程”的情况下,监听端口,建立连接,协商参数。
挑重点的说,比如登录相关线程的函数指针指向如下:
1 fabric->tf_ops.fabric_make_np = &lio_target_call_addnptotpg; 这个函数调用之前就是一些列的初始化,具体的表现在fabric = target_fabric_configfs_init(THIS_MODULE, “iscsi”);,初始化的作用就是利用许多的函数实现具体创建一个完整的target的结构,包括www、tpg、acl等等。有了这些初始化,在函数lio_target_call_addnptotpg调用的时候会根据初始化参数值以及返回值嵌套调用,实现创建SOCKET,绑定,监听socket,以及登录target,安全协商等等。
2在target注册完成之后,就可以看到lio_target_fabric_configfs = fabric(iscsi_target_config.c:1769),lio_target_fabric_configfs是个全局变量,后面还有他的相关调用,这才是注册的真正目的。
四:Iscsi接收线程:iscsi_target_rx_thread(iscsi_target.c:3753),
1收数据之前的准备:
在收发线程之前是为收发线程申请一定的虚拟地址空间具体的函数是iscsi_thread_set_init(),create收发线程。对于收线程来说,收数据前对线程状态的预处理,包括检查收线程状态不是空间闲状态(如果在空闲状态,就会调用kthread_should_stop()函数结束收线程),信号没有屏蔽当前的线程(也就是说如果没有则是收线程随时可以接收到信号进入接收数据的状态),在接收数据完成的时候,设置线程状态为reset,并清除收线程if ((ts->status == ISCSI_THREAD_SET_RESET) && (ts->thread_clear & ISCSI_CLEAR_RX_THREAD)) complete(&ts->rx_restart_comp)。
2收数据的时候:
2.1收数据:ret = rx_data(conn, &iov, 1, ISCSI_HDR_LEN);这个函数会调用kernel_recvmsg(conn->sock, &msg, iov_p, iov_len,(data - total_rx), MSG_WAITALL)函数实现从socket接收48byte的数据
2.2收数据主要是从socket接收数据到buffer,buffer[0]的值按位与(opcode = buffer[0] & ISCSI_OPCODE_MASK),以取得opcode的值,而opcode的值决定了传输过来的pdu类型,比如有:ISCSI_OP_SCSI_CMD,ISCSI_OP_SCSI_DATA_OUT,ISCSI_OP_NOOP_OUT,ISCSI_OP_SCSI_TMFUNC,ISCSI_OP_TEXT,ISCSI_OP_LOGOUT。
2.3对于ISCSI_OP_SCSI_CMD类型的pdu会调用iscsit_handle_scsi_cmd(conn, buffer) 函数实现对pdu的处理,关于这个函数我在“源码读笔记”里面啰里啰嗦的记录了当时的阅读思路,通过添加kprint、debug等初步有所了解,在涉及到读写的pdu时候会有底层的知识,都在这篇文章里面做了记录,如果嫌弃啰嗦,只看主调函数的作用就行。本文也是,主调函数做了一个大致的功能实现说明。
2.4ISCSI_OP_SCSI_DATA_OUT类型 的pdu(iscsi_target.c:3848),调用iscsit_handle_data_out(conn, buffer)来处理,函数主要的功能是接收来自initiator的数据并把正确接受的数据派发到底层,接收函数是: rx_data(conn, &cmd->iov_data[0], iov_count, rx_size)(iscsi_target.c:1354),在接收之前会进行一些检测,比如flag标志位的检测和数据方向的检测(DMA_TO_DEVICE)以及数据的长度检测,如果数据的长度超过了最大的可传输数据段的长度则会报错退出,检测这个的目的主要是看收到的pdu是不是正确的,如果不是正确的pdu就退出没有派发到底层去的必要。在这个里面还有出错恢复重传的调用,对于出错成功传回的数据还是跟普通的数据处理方式一样派发给底层去处理。这个函数的大致内容就这些,其中涉及底层的函数调用是target_execute_cmd(&cmd->se_cmd),此函数的主干调用函数是iblock_execute_rw()函数,跟前面的 iscsit_handle_scsi_cmd(conn, buffer) 函数调用的底层函数是同一个,就不再重复。
2.5ISCSI_OP_NOOP_OUT类型的pdu处理函数是iscsit_handle_nop_out(conn, buffer)。iscsit_handle_nop_out(conn, buffer)函数对接收到的pdu的处理跟data ou类型的函数处理思路有相似的地方,就是检查pdu的类型是否正确检查加收数据的长度是否在iscsi可处理的最大限制范围里面,不同的地方就是如果opcode的类型如果是immediate,则会添加到响应队列,在后面将要说到的发送线程负责发送data in pdu给initiator。
五:Iscsi发送线程:iscsi_target_tx_thread(iscsi_target.c:3702)函数调用了handle_immediate_queue(conn)和 handle_response_queue(conn)函数,实现的功能就是data out pdu的data in pdu发送和r2t pdu等发送给initiator端