tgt服务端流程分析

整体流程

Figure1 tgt流程图

 

 

基本操作

安装tgt包:

yum --enablerepo=epel -y install scsi-target-utils

 

安装完成后,启动 TGT 服务:

# service tgtd start

 

如果想在系统启动时自动启动 TGT 服务,可以使用如下命令:

# chkconfig tgtd on

 

如果想确认 TGT 服务是否启动,可以用 # servicetgtd status 查看服务状态;当然,也可以查询 TGT 服务占用的端口:

# netstat -anlpt | grep 3260

其中,3260 是 TGT 服务的监听端口。结果如下:

创建Target:

tgtadm --lld iscsi --mode target --op new --tid 2--targetname iqn.2012-12.com.example:server.target

查询Target:

tgtadm --lld iscsi--mode target --op show

查询详细信息:

tgtadm --lld iscsi--mode target --op show --tid 2 

创建用作LUN的文件:

ddif=/dev/zero of=/home/lun.bin count=0 obs=1 seek=1G 

添加LUN:(需要关闭SELinux,否则报错invalid)

tgtadm --lld iscsi--mode logicalunit --op new --tid 2 --lun 1 --backing-store /home/lun.bin

修改配置文件需要重启机器:

修改/etc/selinux/config 文件

将SELINUX=enforcing改为SELINUX=disabled

重启机器即可

设置访问权限all:(服务端权限要设到具体IP,否则客户端discover失败)

 tgtadm --lldiscsi --mode target --op bind --tid 2 -I all

tgtadm --lld iscsi--mode target --op bind --tid 2 -I 192.168.56.103

 

 

iscsi initiator 连接(需要关闭服务端防火墙)

systemctl stop firewalld.service

systemctl disable firewalld.service

 

iscsiadm -m discovery -t sendtargets -p 192.168.56.102

 

登录:

iscsiadm -m node --login

 

#登录某一个

#iscsiadm --mode node --targetname iqn.2012-10.net.cpd:san.target01 --portal 172.16.201.200 --login

 

查看核对登录信息

iscsiadm -m session -o show

 

登陆后,fdisk -l 能看到iscsi挂载的服务端设备,然后可以当做正常磁盘设备一样使用。

 

配置tgt编译环境:

去掉doc相关编译,网络连接问题会卡住,

find -name Makefile | xargs grep O2 -R--colour

make DEBUG=yes

make install

然后就可以gdb调试了~

 

tgt流程分析:

http://www.sysnote.org/2014/08/23/tgt-arch/

 

/usr/sbin/tgtd -f

 

tgt锁:

/var/run/tgtd/socket.0.lock

 

清理锁:

rm -f /var/run/tgtd/*

 

杀掉tgtd进程:

kill -9 pid

 

带debug信息调试:

gdb -args /usr/sbin/tgtd -f -d 1

 

 

流程详解

创建target

执行:

tgtadm --lld iscsi --mode target --op new --tid 2--targetname iqn.2012-12.com.example:server.target

 

触发:

mgmt_event_handler

 

main ->ipc_init -> tgt_event_add (mgmt_event_handler )

通过socket来触发事件:/var/run/tgtd/socket.0

tgtadm 的ipc_mgmt_connect触发了tgtd的事件mgmt_event_handler

 

main -> ipc_mgmt_req -> ipc_mgmt_connect

             ipc_mgmt_req -> ipc_mgmt_rsp -> ipc_mgmt_connect

 

用来连接进程。

 

多次触发:

mtask_recv_send_handler 来进行进程间通信。

mtask_recv_send_handler ->mtask_received->mtask_execute ->target_mgmt ->tgt_target_create->tgt_device_create

backing 为 0,不会启动bs工作线程

用来进行具体操作。

 

创建后端存储

执行:

tgtadm --lld iscsi --mode logicalunit --op new --tid 2--lun 1 --backing-store /home/lun.bin

 

触发:

mgmt_event_handler(添加了管理事件处理)

mtask_recv_send_handler ->mtask_received->mtask_execute -> device_mgmt -> tgt_device_create ->bs_rdwr_init ->bs_thread_open->bs_thread_worker_fn

 

 

 

在执行new 后端时,会调用 bs_rdwr_init从而开启bs_thread_worker_fn.

创建设备时,创建了16个bs工作线程。

 

 

 

 

设置客户端访问IP

执行:

tgtadm --lld iscsi --mode target --op bind --tid 2 -I192.168.56.103

 

触发:

mgmt_event_handler

mtask_recv_send_handler ->mtask_received->mtask_execute -> target_mgmt ( OP_BIND )

 

 

客户端登录

执行:

iscsiadm -m node --login

 

触发:

accept_connection/ iscsi_tcp_event_handler

 

accept_connection 用于连接客户端,iscsi_tcp_event_handler用于处理各种客户端的请求。

 

 

事件相关

list_add(&tev->e_list, &tgt_events_list);

事件具体信息被加入到tgt_events_list中

 

tgt_event_add中将事件句柄加入ep_fd代表的实体

    err = epoll_ctl(ep_fd, EPOLL_CTL_ADD, fd, &ev);

 

ep_event_modify 可以修改事件为EPOLLOUT

 

 

网络端口初始化

tcp初始化流程:main->lld_init ->lld_init_one ->iscsi_init ->iscsi_tcp_init->iscsi_add_portal ->iscsi_add_portal ->iscsi_tcp_init_portal

 

 

 

3260是监听端口

getaddrinfo 来获取socketaddr结构链表

https://baike.baidu.com/item/getaddrinfo/9021771

 

一个tcp socket对应两个句柄:IPv4 &IPv6

 

 

块设备相关初始化

main ->bs_init ->bs_init_signalfd (bs_sig_request_done)

 

 

 

优先使用信号量通知,其次使用线程间通知

信号量对应的处理函数是bs_sig_request_done。

 

 

bs_thread_worker_fn 中 kill(getpid(),SIGUSR2)来发信号触发bs_sig_request_done

 

 

 

sbc初始化

main执行前sbc_init初始化,注册sbc_template到device_type_list

tgt_device_create时将sbc_template加入lu中

 

 

 

初始化后scsi_cmd_perform中才能根据操作码op来找到对应的操作cmd_perform。

 

数据处理流程

iscsiadm -m node --login

客户端登录服务端以后,就产生了一些iscsi_tcp事件需要服务端处理。

 

 

主线程会触发事件:iscsi_tcp_event_handler

 

accept_connection 中定义了事件iscsi_tcp_event_handler

 

 

bs_thread_cmd_submit 激活了 bs_thread_worker_fn中的pthread_cond_wait

 

注:pthread_cond_wait是多线程抢占式的,pthread_cond_signal发信号,谁抢到了锁,谁去用,没抢到的while再次阻塞等待

 

以数据读写为例

iscsi_tcp_event_handler -> iscsi_rx_handler-> iscsi_task_rx_done -> iscsi_task_queue-> iscsi_task_execute -> iscsi_target_cmd_queue-> target_cmd_perform -> scsi_cmd_perform -> sbc_rw (以读写为例)

 

#0  bs_thread_cmd_submit(cmd=0x66abe0) at bs.c:464

#1  0x000000000042d938 in sbc_rw (host_no=0, cmd=0x66abe0) at sbc.c:399

#2  0x00000000004253a1 in scsi_cmd_perform(host_no=0, cmd=0x66abe0) at scsi.c:541

#3  0x0000000000420d59 in target_cmd_perform(tid=2, cmd=0x66abe0) at target.c:1168

#4  0x0000000000420c73 in target_cmd_queue(tid=2, cmd=0x66abe0) at target.c:1150

#5  0x000000000040c2f4 iniscsi_target_cmd_queue (task=0x66ab10) at iscsi/iscsid.c:1387

#6  0x000000000040c3c2 iniscsi_scsi_cmd_execute (task=0x66ab10) at iscsi/iscsid.c:1407

#7  0x000000000040c792 in iscsi_task_execute(task=0x66ab10) at iscsi/iscsid.c:1527

#8  0x000000000040cbac in iscsi_task_queue(task=0x66ab10) at iscsi/iscsid.c:1614

#9  0x000000000040d2ca in iscsi_task_rx_done(conn=0x666000) at iscsi/iscsid.c:1744

#10 0x000000000040e675 in iscsi_rx_handler(conn=0x666000) at iscsi/iscsid.c:2222

#11 0x0000000000416739 in iscsi_tcp_event_handler (fd=14,events=1, data=0x666000) at iscsi/iscsi_tcp.c:278

#12 0x000000000041b500 in event_loop () at tgtd.c:432

#13 0x000000000041be05 in main (argc=2,argv=0x7fffffffe628) at tgtd.c:624

 

bs_thread_cmd_submit将cmd->bs_list加到 info->pending_list上

bs_thread_cmd_submit-> pthread_cond_signal 来激活bs_thread_worker_fn

 

bs_thread_worker_fn 中的 info 和 bs_thread_cmd_submit 中的 info 是指向同一块内存x单元(gdb证实)

 

bs_thread_worker_fn 中从info->pending_list上取下cmd

 

bs_rdwr_request从设备句柄fd里读出信息到scsi的buffer中,这个函数应该是底层块设备的具体操作了。

 

 

 

 

数据存在 cmd->in_sdb.buffer

 

将cmd->bs_list加入到finished_list

 

bs_thread_worker_fn中kill发信号SIGUSR2触发bs_sig_request_done,sig_fd

随后通过事件触发主线程执行bs_sig_request_done

 

bs_sig_request_done ->target_cmd_io_done->iscsi_scsi_cmd_done -> iscsi_event_modify (改事件为 EPOLLOUT)-> tgt_event_modify

将task加入task->conn->tx_clist由主线程处理

tgt_event_modify -> epoll_ctl打断主线程的epoll_wait睡眠,让主线程及时处理tx事件。

 

iscsi_tx_handler ->iscsi_task_tx_start-> iscsi_data_rsp_build 将读取的数据存在conn->rsp.data中

 

 

conn->rsp.data

写完rsp数据给客户端,事件变回EPOLLIN

iscsi_tx_handler -> ep_write_end( iscsi_tcp_write_end)

 

 

 

以上基本上就是一个完整的服务端读操作,响应给客户端的流程细节。

 

服务端上数据的读或写是由客户端控制的req->cdb传值给cmd->scb

 

 

bs_rdwr_request 中根据cmd->scb[0]来对块设备进行操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值