Linux中的SCSI模型及iSCSI示例

本文深入探讨Linux内核中SCSI设备的复杂驱动架构,解析SCSI子系统的三层结构及其在设备发现过程中的作用。重点分析iSCSI设备发现流程,包括session与连接的创建,以及目标器扫描过程,揭示Linux操作系统如何识别和处理SCSI及iSCSI存储设备。

在Linux内核中SCSI驱动应该是最为复杂的驱动,没有之一。因为对于整个SCSI系统来说,不只包含一种类型的设备,而是一类设备。前面文章我们简单介绍了Linux操作系统内核中SCSI子系统的整体架构,我们这里简单回忆一下。

在Linux内核中抽象了一个称谓SCSI总线的虚拟总线。而在SCSI总线上又包含SCSI的驱动和设备。

Linux中的SCSI模型及iSCSI示例

图1 SCSI体系结构

Linux操作系统中的SCSI整个架构分为3层,各层的具体作用如下:

中间层,用于实现SCSI的公共功能,比如错误处理等。

高层或上层,它代表各种scsi设备类型的驱动,如scsi磁盘驱动,scsi磁带驱动,高层驱动认领低层驱动发现的scsi设备,为这些设备分配名称,将对设备的IO转换为scsi命令,交由低层驱动处理。

底层或下层,它代表与SCSI的物理接口的实际驱动器,主要为各个厂商为其特定的主机适配器(Host Bus Adapter, HBA)驱动,例如: FC卡驱动、SAS卡驱动和iSCSI(iSCSI可以使硬件HBA卡或者基于普通网卡的软件实现)等。

SCSI设备的发现

SCSI设备通常是支持热插拔(即插即用)的,也就是可以直接连接目标设备,并在Linux操作系统看到并使用。比如我们常见优盘可以插上之后马上使用,而不需要重启电脑。而在企业级服务器中的SAN存储也是通过光纤连接后在Linux服务可以看到磁盘设备(当然需要在存储端有相关的配置)。为了后续内容的理解,本节将介绍在设备物理连接就绪的情况下,在Linux服务器中如何呈现设备(专业术语叫扫描发现)。

我们日常连接存储设备的方式有很多种,除了最常见的优盘、光盘外,还有企业上常用的FC-SAN、IP-SAN和SAS磁盘阵列等。我们今天主要介绍一下FC-SAN和IP-SAN这两种连接存储设备的方式。

对于FC-SAN存储,当建立的Linux服务器与存储设备的物理连接,且存储设备做过必须的配置之后,可以通过如下几种方式在Linux服务程序磁盘设备。

  1. 重启主机
  2. 卸载并重新加载主机适配器驱动
  3. 通过echo /sys文件系统(仅适用于2.6内核版本)重新扫描总线
  4. 通过echo /proc或/sys文件系统手动添加和删除SCSI磁盘

这几种方式的本质是一样的,其实就是对总线上的设备进行重新扫描,发现新加入的设备,并在内核中创建必要的内核数据结构,然后呈现给用户。前者自不必说,我们看一下后2者是如何进行操作的。

以下命令可扫描所有通道、target、LUN和主机。

echo “- - -” > /sys/class/scsi_host/hostH/scan

其中hostH中H是变化的,需要根据具体的适配卡(HBA)灵活调整。

可通过以下命令删除或对SCSI磁盘取消配置:

echo "scsi remove-single-device H B T L" > /proc/scsi/scsi

命令示例中,H, B, T, L代表设备的主机,总线,target,和LUN ID。

对于IP-SAN的操作要简单的多,前面我们介绍过启动器端的配置管理的命令。该命令中有一个登陆操作,在进行登陆的时候其实就相当于进行设备的扫描,此时会建立新的设备,并呈现给用户。关于具体操作本文不再赘述,具体可以参考之前的文章。

上面命令是关于设备扫描的基本操作,这里作为一个简单的入门,后续针对代码做详细的介绍。

Linux内核发现设备的原理

前文我们介绍过,SCSI的上层中sd的驱动其实就是一个SCSI磁盘驱动,它呈现给我们的是一个磁盘设备。而底层的FC Driver则是FC-HBA卡的驱动。两者结合就形成了我们在操作系统层面看到的基于FC-SAN的磁盘。因此,Linux操作系统发现设备的过程其实就是上述两个驱动创建实例(数据结构)的过程

SCSI设备复杂的地方在于FC-HBA卡还可能包含多个通道,而存储设备又可能包含多个目标器,目标器中又可能有多个设备(LUN)。因此,对应关系变得非常复杂。在Linux操作系统中通过一个四元组(host,channel,target,lun)来标识这种关系。这种组织关系在内核中也有对应的数据结构。如图2是SCSI四元组的逻辑关系。

Linux中的SCSI模型及iSCSI示例

图2 SCSI四元组

上述概念在Linux内核中有3个对应的数据结构,分别是Scsi_Host、scsi_target和scsi_device。

Linux中的SCSI模型及iSCSI示例

图3 核心数据结构关系

上面3个核心数据结构中,Scsi_Host是适配器(HBA)对应的数据结构,位于SCSI总线下面。scsi_target对应着一个目标器设备,目标器设备未必是物理的,也可能是虚拟的。而scsi_device则为目标器中的设备,可以理解为存储中的LUN在客户端的体现。

观察一下图3,可以看出在Scsi_Host下面通过链表的方式存储着多个scsi_target,而scsi_target下面又通过链表存储着多个scsi_device。这种关系只是我们在图2中描述的物理对应关系。

内核中除了这三个主要的数据结构外,还有一些辅助的数据结构,比如scsi_host_template和scsi_transport_template等数据结构,这些数据结构主要是完成一些公共的功能。比如对于SCSI设备,有磁盘、光驱和磁带等等,但这些设备有一些公共的功能,因此内核中将这些公共的功能提取成模板。这样,在初始化设备的时候可以借助模板减少初始化的复杂度。

设备发现的iSCSI实例分析

本节结合iSCSI分析一下在SCSI设备中的设备发现流程,通过这个流程及关键数据结构的了解,对整个SCSI和iSCSI就可以有一个概括的了解

在介绍设备发现之前,我们先看一下在Linux操作系统中iSCSI的整体软件架构。如图4所示,整个iSCSI启动器(客户端)的软件架构图包括用户态和内核态两部分的内容。其中用户态主要负责管理,包括iscsiadm命令行工具和iscsid守护进程。而内核态包括如图中绿色的4个内核模块,这些内核模块与SCSI子系统结合起来形成了整个功能。

Linux中的SCSI模型及iSCSI示例

图4 iSCSI软件架构

对于一个管理命令,通常是iscsiadm命令行通过本地套接字发送给iscsid守护进程,而该守护进程经过处理后通过netlink发送到内核模块进行处理。关于整个流程还是比较复杂的,本文暂时不做介绍,后续文章再进行详细的分析。

本文我们需要知道的是在iSCSI中启动器和目标器之间是通过session维护两者之间的关系,而每个session中可能不止有一条连接。但只要建立连接之后,在Linux操作系统中就可以看到磁盘设备(当然,前提是存储端已经做过相关配置)。对于session中的连接数量,设计为可以在同一session中有多条连接的目的是为了可以实现物理链路的冗余,这样可以保证某条链路故障的情况下可以通过其它链路继续提供服务。

废话说了半天,我们当前只需要知道在启动器和目标器之间建立session之后,也就是目标器登录之后,就可以在启动器端看到磁盘,这个也就是设备发现的过程。因此,这里核心就是分析iSCSI中创建session的过程

这里所说的创建session的过程其实是个宽泛的概念,其实在Linux最终实现时是分2步进行的,第一个是创建session,此时是创建必要的数据结构和进行处理函数的初始化等工作;而第2步则是创建session中的一个连接,这个连接创建成功后,session才能真正起作用。

1) 创建session

我们这里忽略不必要的细节,从内核中创建session流程讲起。其入口函数是iscsi_if_create_session,该函数在文件scsi_transport_iscsi.c中,在该函数中完成了所有功能。但该函数是调用其它函数实现的,具体如图所示。

Linux中的SCSI模型及iSCSI示例

图5 内核创建session流程

对于纯软件的iSCSI其实是调用了iscsi_sw_tcp_session_create函数,而该函数则通过iscsi_host_alloc分配一个Scsi_Host实例,并通过iscsi_session_setup完成session的设置。

我们前面提到过host其实对应着硬件的适配卡,适配卡是Linux客户端与存储端(服务端)通信的通道,即使是纯软件的情况下内核也会创建这样一个数据结构,只不过通信的方式是通过TCP协议。而在函数iscsi_host_alloc中正是完成了该结构体的分配和部分初始化工作。

函数iscsi_session_setup则是进行session的创建和初始化,核心是将iscsi_sw_tcp_transport函数集初始化到session当中,这样在后续的操作中就可以使用该函数集中的函数。最终,该函数会将创建的session添加到全局session链表sesslist中。

2) 创建连接

前面创建了一个session,这里就是要建立连接了。建立连接也是由iscsiadm命令行发起的。最终触发到内核态的函数接口。该函数接口为iscsi_conn_start

Linux中的SCSI模型及iSCSI示例

图6 启动连接主要流程

通过图6的流程可以看出来,启动连接的本质其实是扫描目标器。扫描目标器也就是看看是否有新的目标器,并且目标器上是否有新的LUN。如果有新的设备加入,则需要创建对应的数据结构。

Linux中的SCSI模型及iSCSI示例

图7 扫描目标器主要流程

扫描目标器的函数为__scsi_scan_target,该函数一个SCSI子系统的公共函数。不仅仅iSCSI要用到该函数,基于FC和iSCSI HBA卡的驱动也要用到该函数。

继续分析该函数内部的实现,这里面有几个比较核心的函数需要介绍一下。scsi_alloc_target函数用于分配一个目标器结构体,并进行必要的初始化。scsi_alloc_sdev函数是创建scsi_device结构体,并进行必要的初始化,这个设备就是与具体磁盘对应的设备。这里面比较重要的是初始化了请求队列。这个队列用于处理读写数据,我们在后面介绍读写数据的流程的时候会介绍到。

	if (shost_use_blk_mq(shost))
		sdev->request_queue = scsi_mq_alloc_queue(sdev);
	else
		sdev->request_queue = scsi_alloc_queue(sdev);

最后一个比较重要的函数是scsi_add_lun,这个函数是进行设备扫描的重头戏。它最终会掉到sd驱动(也就是SCSI磁盘驱动)的sd_probe函数,该函数完成创建磁盘和与设备关联的相关操作。简单的说,这个函数完成后在用户层面就可以看到磁盘,并且该磁盘与底层的驱动建立了关联。这样,当用户对磁盘进行读写操作的时候,请求就可以经过底层的驱动(以太网卡,iSCSI-HBA或者FC-HBA)发送到存储端。

Linux中的SCSI模型及iSCSI示例

 

本文并没有介绍每个函数的细节,只是介绍了大体的流程。主要是考虑到贴代码代码会导致文章太乱,也不利于表达。后面本号在写一篇关于IO的文章,这样就比较清楚的了解了数据是如何从用户的应用到存储设备了。

<think>好的,我现在需要帮助用户寻找关于通过Barrier Functions实现端到端安全强化学习的论文复现方法或代码,特别是针对《End-to-End Safe Reinforcement Learning through Barrier Functions for Safety-Critical Continuous Control Tasks》这篇论文。首先,我得先理解用户的具体需求。用户可能已经读过这篇论文,现在想要复现其中的实验或算法,但可能缺乏具体的代码或实现步骤的指导。 接下来,我应该考虑这篇论文的核心内容。根据标题,论文主要结合了Barrier Functions和安全强化学习,用于安全关键的连续控制任务。Barrier Functions通常用于保证系统状态在安全区域内,而强化学习则用于优化控制策略。因此,复现的关键可能在于如何将这两者结合起来,设计合适的算法框架。 用户提到参考了文献[^1],即参考文献6,但用户提供的引用信息可能不完整,需要确认是否正确。不过,这可能是指论文本身引用的其他文献,所以暂时不需要深究这点,而是专注于用户的问题。 接下来,我需要思考复现这篇论文可能需要的步骤。通常,复现论文需要以下几个步骤:理解算法框架、获取或实现Barrier Functions、搭建强化学习环境、设计安全约束的集成方式,以及实验验证。此外,代码的实现可能需要使用常见的强化学习库,如TensorFlow、PyTorch,或者安全验证工具如CVXPY、CORA等。 用户可能需要具体的代码示例或资源链接。但考虑到论文的具体实现可能没有公开的代码,我需要考虑替代方案,比如建议用户参考类似的开源项目,或者分步骤指导如何构建关键组件。例如,Barrier Functions的实现可能需要数学建模,而安全强化学习的部分可能需要修改现有的RL算法来纳入安全约束。 另外,用户可能对如何验证复现结果有疑问,比如使用哪种仿真环境(如MuJoCo、PyBullet)或测试基准。因此,在回答中需要涵盖这些方面,并提供可能的资源链接,如GitHub仓库、相关库的文档等。 还需要考虑用户的技术背景。如果用户对强化学习和控制理论有一定了解,但缺乏具体的实现经验,那么分步骤的指导和代码片段会很有帮助。同时,提醒用户注意论文中的细节,如参数设置、安全约束的具体形式,以及实验部分的复现可能需要的计算资源。 最后,生成相关问题,帮助用户深入理解复现过程中的其他方面,比如如何设计Barrier Functions、如何处理安全约束与奖励函数的平衡,以及如何验证算法的安全性等。</think>关于《End-to-End Safe Reinforcement Learning through Barrier Functions for Safety-Critical Continuous Control Tasks》的论文复现,以下是分步骤的实现建议和资源指引: --- ### **1. 理解论文核心框架** 论文的核心是通过屏障函数(Barrier Functions)将安全约束直接嵌入强化学习的策略优化过程,实现端到端的安全保障[^1]。关键组件包括: - **安全屏障函数设计**:构造满足$h(x) \geq 0$的安全区域,并通过导数约束$\\dot{h}(x) + \lambda h(x) \geq 0$保证状态不越界。 - **策略优化与安全约束的融合**:将屏障函数作为硬约束或惩罚项整合到强化学习的奖励函数中。 --- ### **2. 复现所需工具** | 组件 | 推荐工具 | |-----------------|--------------------------------------------------------------------------| | 强化学习框架 | PyTorch, TensorFlow, Stable Baselines3 | | 控制仿真环境 | OpenAI Gym(自定义安全约束环境)、MuJoCo、PyBullet | | 屏障函数计算 | CVXPY(凸优化)、CORA(可达性分析工具包) | | 安全验证 | Drake(机器人控制验证工具) | --- ### **3. 关键代码实现示例** #### **屏障函数定义(Python)** ```python import torch class BarrierFunction: def __init__(self, lambda_param=0.1): self.lambda_param = lambda_param # 安全衰减系数 def h(self, state): # 定义安全区域,例如:h(x) = x² - 1(状态x需在[-1,1]内) return state.pow(2).sum(dim=1) - 1.0 def h_dot(self, state, action): # 计算h的导数,假设系统动力学模型为已知函数f(x) + g(x)u # 需根据实际环境动力学实现 grad_h = 2 * state dynamics = self.system_dynamics(state, action) # 占位符,需替换为实际模型 return torch.matmul(grad_h, dynamics.T) def safety_constraint(self, state, action): # 屏障约束条件:h_dot + λh ≥ 0 h_val = self.h(state) h_dot_val = self.h_dot(state, action) return h_dot_val + self.lambda_param * h_val ``` #### **安全约束集成到PPO算法(伪代码)** ```python from stable_baselines3 import PPO class SafePPO(PPO): def __init__(self, barrier_fn, *args, **kwargs): super().__init__(*args, **kwargs) self.barrier_fn = barrier_fn def train(self): # 重写训练逻辑,在策略更新中加入安全约束 for batch in rollout_data: states, actions = batch.observations, batch.actions safety_violation = self.barrier_fn.safety_constraint(states, actions) # 将安全违规作为惩罚项加入损失函数 loss = policy_loss - 10 * torch.relu(-safety_violation).mean() loss.backward() ``` --- ### **4. 复现资源推荐** 1. **开源项目参考**: - [Safe Control Gym](https://github.com/utiasDSL/safe-control-gym):包含安全强化学习的基准环境。 - [BarrierNet](https://github.com/MIT-REALM/BarrierNet):屏障函数与神经网络结合的PyTorch实现。 2. **论文相关实现**: - 联系作者获取实验代码(部分论文提供GitHub链接)。 - 参考相似工作如[Safe RL with Control Barrier Functions](https://arxiv.org/abs/1910.06945)的官方实现。 --- ### **5. 验证与调试建议** 1. **简单环境测试**:先在低维环境(如倒立摆)中验证屏障函数的有效性。 2. **安全指标监控**:记录训练过程中的约束违反次数和奖励曲线。 3. **对比实验**:与无安全约束的RL算法(如原始PPO)对比性能与安全性。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数据存储张

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值