利用UDEV机制固定存储设备的名称

本文详细介绍了udev的功能及工作原理,包括udev如何动态管理设备目录、udev的组成及其规则文件的应用。此外,还提供了两个实用示例,展示如何利用udev规则来自定义设备名称。
什么是udev
  udev为一些实际的设备提供了一个动态的设备目录,这些目录里包含这些实际设备所对应的文件。它创建或移除在/dev目录里的设备节点文件,或者重命名网络接口。
  通常udev运行udevd,如果一个设备增加进系统或者从系统中移除,它就会直接从内核中接受到这个udev的事件。
  如果udev接受到一个设备事件,它就会从它的配置(或是规则)文件(有三个位置/etc/udev/rules.d、/dev/.udev/rules.d、/lib/udev/rules.d)中去匹配从sysfs中得到的设备属性来辨识这个设备。这些rules配置文件会去比较所提供的附加(新增加进来的)的设备的信息或者指定一个设备节点名并操作符号链接名来指示udev运行附加的程序来作为设备事件的处理。

udev的组成
  udev由namedev、libsysfs和udev三部分组成。其中,namedev是设备命名子系统;libsysfs提供访问sysfs文件系统,并从中获取信息的标准接口;udev提供/dev设备节点文件的动态创建和删除策略。udev程序负责namedev和libsysfs库交互的任务,当/sbin/hotplug程序被内核调用时,udev将运行。
  udev有很多以.rules为后缀的规则文件,以行为单位,除去以“#”开头的代表注释的行外,每一行代表一个规则。每个规则分成一个或多个匹配和赋值部分。匹配部分用匹配专用的关键字来表示,相应的赋值部分用专用的关键字来表示。

udev的工作原理
  设备节点的创建,是通过sysfs接口分析dev规则文件取得设备节点号。udevd通过netlink socket通讯机制在内核和用户空间之间传递信息,来得知内核里模块的变化情况,通过hotplug机制得知设备的插入移除情况。
  内核调用kobject_uevent函数发送netlink message给用户空间,这部分工作通常无需驱动去自己处理,在统一设备模型里面,在子系统这一层面,已将这部分代码处理好了,包括在设备对应的特定的Kobject创建和移除的时候都会发送相应add和remove消息,当然前提是您在内核中配置了hotplug的支持。
  Netlink socket作为一种内核和用户空间的通信方式,不仅用在hotplug机制中,同样还应用在其他很多真正和网络相关的内核子系统中。Udevd通过标准的socket机制,创建socket连接来获取内核广播的uevent事件并解析这些uevent事件。

应用
  要使用udev自定义设备名,就需要获取到设备的相关且唯一的信息,用于书写udev规则:
在rhel5,可以使用udevinfo -a -p $(udevinfo -q path -n /dev/sdb)来获取设备信息,在rhel6,使用udevadm info -a -n /dev/sdb来获取设备信息。
  针对iscsi设备,使用udevadm info -a -n /dev/sdb可能获取不到类似序列号之类的信息,可以使用udevadm info -q all -n /dev/sdb试试,但是通常我们会这么去使用,在rhel5, scsi_id -g -s $(udevinfo -q path -n /dev/sdc)获取信息,在rhel6,scsi_id --whitelisted --replace-whitespace /dev/sdc获取信息,用作书写udev规则。

下面看看例子:
例一:
如我们rhel6系统插入了一个u盘,自动识别为/dev/sdb,而我们希望将其固定为/dev/MyUsbDisk。

则我们可以使用udevadm info -a -n /dev/sdb获取到ATTRS{serial}=="AC681DEB"信息,书写如下规则即可。
KERNEL=="sd*", SUBSYSTEMS=="usb",ATTRS{serial}=="AC681DEB",NAME="MyUsbDisk"


例二:
rhel6下,已经挂载一个iscsi target端导出的存储,没写udev规则之前,自动识别为sdc,我们想将这个iscsi存储的节点固定为叫做Idisk,如果做了分区,则sdc1固定为Idisk1。
我们书写一个udev规则
KERNEL=="sd*", SUBSYSTEM=="block", PROGRAM="/sbin/scsi_id --whitelisted --replace-whitespace /dev/$name", RESULT=="1IET_00010001",NAME="Idisk%n"
内核检测信息是sd*,子系统信息为块设备,执行程序scsi_id --whitelisted --replace-whitespace /dev/$name,结果为1IET_00010001,则重命名节点为Idisk%n,   $name为内核检测出信息是sdb则$name=sdb,%n为内核检测信息为sdb,则%n为空,检测信息为sdb1,则%n为1,这么写的作用在于挂载iscsi导出的一个lun后,我们对这个lun进行分区的情况,如果一个lun为一个分区,则无需写上%n。

扩展:
  用如下规则之一也可实现上条规则的效果,只是上条规则在iscsi设备login时能触发,如下两条规则必须由udev触发,如手动start_udev。所以通常应使用上述规则较好。
KERNEL=="sd*", SUBSYSTEM=="block", PROGRAM="/sbin/udevadm info -q all -n /dev/$name", RESULT=="*beaf11*", NAME="Idisk%n"
KERNEL=="sd*", SUBSYSTEM=="block", PROGRAM="/sbin/udevadm info -q all -p %p", RESULT=="*beaf11*", NAME="Idisk%n"

关于udev的调试:
udevadm trigger是udev触发器,执行此指令也是触发rules规则,执行结果同start_udev。
udevadm test /block/sdc可以看到udev规则执行流程,显示出来的信息较多,需要从中提取需要的信息,达到调试的目的。

### Windows 固定设备 COM 串口号设置方法 在 Windows 系统中,可以通过修改 USB 设备的供应商 ID (VID) 和产品 ID (PID),以及序列号 (Serial Number),使系统识别该设备为同一硬件并分配固定的 COM 号。以下是具体实现方式: #### 修改 USB CDC 类描述符 USB CDC 类描述符定义了设备的基本属性,包括 VID、PID 和序列号。这些字段决定了 Windows 是否将新接入的设备视为已知设备。为了确保每次接入时使用相同的 COM 口,需统一所有设备的以下参数: - **VID**: 厂商唯一标识。 - **PID**: 产品唯一标识。 - **序列号**: 区分同类型设备的唯一标志。 通过调整固件中的 USB 描述符部分,可以强制所有设备报告完全一致的信息。例如,在 MH2103 的 USB CDC 实现中,可编辑其源码以硬编码固定的序列号[^1]。 #### 更新注册表项 当 USB 设备首次插入计算机时,Windows 将基于其硬件 ID 创建一条记录于系统的设备管理器数据库之中。此过程涉及存储特定实例路径下的配置详情至 `HKEY_LOCAL_MACHINE` 下的相关键值位置。如果希望更改现有装置所关联之端口号码,则可通过手动干预达成目标。 假设当前动态分配给某款 USB 转 RS232 模块的是 COM3,并期望将其锁定为此数值而不随日后重新插拔而变动的话,请按照下面指示操作: 1. 打开运行对话框(`Win + R`),输入`regedit`启动注册表编辑程序; 2. 定位到节点:`Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\<YourDeviceIdentifier>\Device Parameters`; 3. 寻找名为"PortName"字符串型态条目,双击后设定成想要保留下来的通讯埠名称形式如:"COM3"[^2]. 值得注意的是,上述步骤里的 `<YourDeviceIdentifier>` 应替换为你实际使用的外设对应的完整标识符字符串,通常类似于 `USB\VID_XXXX&PID_YYYY` 结构。 对于 Linux 平台而言,虽然提供了 udev 规则机制允许管理员自定义逻辑链接指向真实的 TTY 文件从而间接达到类似效果[^3] ,但在微软操作系统环境下并无直接等价功能可用;因此主要依赖前期设计阶段即妥善规划好各项必要参数来规避后续频繁变更带来的困扰。 ```python import winreg as reg def set_fixed_com_port(device_identifier, desired_com_port): key_path = r'SYSTEM\CurrentControlSet\Enum\USB\\' + device_identifier + '\\Device Parameters' try: # Open the registry key for writing. key = reg.OpenKey(reg.HKEY_LOCAL_MACHINE, key_path , 0, reg.KEY_SET_VALUE) # Set the PortName value to our desired COM port number. reg.SetValueEx(key,"PortName", None, reg.REG_SZ,str(desired_com_port)) # Close the opened key after modification is done. reg.CloseKey(key) return True except Exception as e: print(f"Error setting fixed COM port: {e}") return False ``` 以上 Python 函数示范了如何利用标准库访问 Windows 注册表 API 来自动化完成指定 USB 外设绑定恒定虚拟串行接口的任务流程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值